diff --git a/0001-add-base-files-for-libphtread-condition-family.patch b/0001-add-base-files-for-libphtread-condition-family.patch new file mode 100644 index 0000000000000000000000000000000000000000..9ca2225dded2b164973ff28df730096b2ffb07df --- /dev/null +++ b/0001-add-base-files-for-libphtread-condition-family.patch @@ -0,0 +1,2321 @@ +From 76a50749f7af5935ba3739e815aa6a16ae4440d1 Mon Sep 17 00:00:00 2001 +From: Ulrich Drepper +Date: Tue Nov 26 22:50:54 2002 +0000 +Subject: [PATCH 1/9] 0001 + +since https://sourceware.org/git/?p=glibc.git;a=commit;h=ed19993b5b0d05d62cc883571519a67dae481a14 +delete pthread_condtion function.However, using these interfaces has better performance. +Therefore, we add a subpacket to use these interfaces. +you can use it by adding LD_PRELOAD=./libpthreadcond.so in front of your program (eg: +LD_PRELOAD=./libpthreadcond.so ./test). use with-compat_2_17 to compile it. +WARNING:2.17 version does not meet the posix standard, you should pay attention when using it. +add pthread_cond_clockwait to prevent process hang up when libpthread-2.17 and libpthread-2.28 are used together. +use pthread_cond_common to implement the public functions of pthread_cond_clockwait,pthread_cond_clockwait and pthread_cond_timedwait. + +Add some base files for the libpthread_condition family. +Including but not limited to the following submission: +6efd481484e +a88c9263686 +76a50749f7a +69431c9a21f +5bd8a24966d + +--- + nptl_2_17/cancellation_2_17.c | 60 ++ + nptl_2_17/cleanup_compat_2_17.c | 50 ++ + nptl_2_17/pthread_cond_broadcast_2_17.c | 101 +++ + nptl_2_17/pthread_cond_destroy_2_17.c | 86 +++ + nptl_2_17/pthread_cond_init_2_17.c | 49 ++ + nptl_2_17/pthread_cond_signal_2_17.c | 84 +++ + nptl_2_17/pthread_cond_wait_2_17.c | 329 ++++++++++ + nptl_2_17/pthread_condattr_getclock_2_17.c | 28 + + nptl_2_17/pthread_condattr_getpshared_2_17.c | 28 + + nptl_2_17/pthread_condattr_init_2_17.c | 33 + + nptl_2_17/pthread_condattr_setclock_2_17.c | 45 ++ + nptl_2_17/pthread_mutex_cond_lock_2_17.c | 21 + + nptl_2_17/pthread_mutex_lock_2_17.c | 652 +++++++++++++++++++ + nptl_2_17/pthread_mutex_unlock_2_17.c | 361 ++++++++++ + nptl_2_17/tpp_2_17.c | 195 ++++++ + nptl_2_17/vars_2_17.c | 43 ++ + 16 files changed, 2165 insertions(+) + create mode 100644 nptl_2_17/cancellation_2_17.c + create mode 100644 nptl_2_17/cleanup_compat_2_17.c + create mode 100644 nptl_2_17/pthread_cond_broadcast_2_17.c + create mode 100644 nptl_2_17/pthread_cond_destroy_2_17.c + create mode 100644 nptl_2_17/pthread_cond_init_2_17.c + create mode 100644 nptl_2_17/pthread_cond_signal_2_17.c + create mode 100644 nptl_2_17/pthread_cond_wait_2_17.c + create mode 100644 nptl_2_17/pthread_condattr_getclock_2_17.c + create mode 100644 nptl_2_17/pthread_condattr_getpshared_2_17.c + create mode 100644 nptl_2_17/pthread_condattr_init_2_17.c + create mode 100644 nptl_2_17/pthread_condattr_setclock_2_17.c + create mode 100644 nptl_2_17/pthread_mutex_cond_lock_2_17.c + create mode 100644 nptl_2_17/pthread_mutex_lock_2_17.c + create mode 100644 nptl_2_17/pthread_mutex_unlock_2_17.c + create mode 100644 nptl_2_17/tpp_2_17.c + create mode 100644 nptl_2_17/vars_2_17.c + +diff --git a/nptl_2_17/cancellation_2_17.c b/nptl_2_17/cancellation_2_17.c +new file mode 100644 +index 00000000..5c9ce572 +--- /dev/null ++++ b/nptl_2_17/cancellation_2_17.c +@@ -0,0 +1,60 @@ ++/* Copyright (C) 2002-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Ulrich Drepper , 2002. ++ ++ 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 ++ . */ ++ ++#include "pthreadP_2_17.h" ++#include ++#include ++#include ++ ++int ++__pthread_enable_asynccancel (void) ++{ ++ struct pthread *self = THREAD_SELF; ++ ++ int oldval = THREAD_GETMEM (self, canceltype); ++ THREAD_SETMEM (self, canceltype, PTHREAD_CANCEL_ASYNCHRONOUS); ++ ++ int ch = THREAD_GETMEM (self, cancelhandling); ++ ++ if (self->cancelstate == PTHREAD_CANCEL_ENABLE ++ && (ch & CANCELED_BITMASK) ++ && !(ch & EXITING_BITMASK) ++ && !(ch & TERMINATED_BITMASK)) ++ { ++ THREAD_SETMEM (self, result, PTHREAD_CANCELED); ++ __do_cancel (); ++ } ++ ++ return oldval; ++} ++libc_hidden_def (__pthread_enable_asynccancel) ++ ++/* See the comment for __pthread_enable_asynccancel regarding ++ the AS-safety of this function. */ ++void ++__pthread_disable_asynccancel (int oldtype) ++{ ++ /* If asynchronous cancellation was enabled before we do not have ++ anything to do. */ ++ if (oldtype == PTHREAD_CANCEL_ASYNCHRONOUS) ++ return; ++ ++ struct pthread *self = THREAD_SELF; ++ self->canceltype = PTHREAD_CANCEL_DEFERRED; ++} ++libc_hidden_def (__pthread_disable_asynccancel) +diff --git a/nptl_2_17/cleanup_compat_2_17.c b/nptl_2_17/cleanup_compat_2_17.c +new file mode 100644 +index 00000000..53cf903d +--- /dev/null ++++ b/nptl_2_17/cleanup_compat_2_17.c +@@ -0,0 +1,50 @@ ++/* Copyright (C) 2002-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Ulrich Drepper , 2002. ++ ++ 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 ++ . */ ++ ++#include "pthreadP_2_17.h" ++#include ++ ++ ++void ++_pthread_cleanup_push (struct _pthread_cleanup_buffer *buffer, ++ void (*routine) (void *), void *arg) ++{ ++ struct pthread *self = THREAD_SELF; ++ ++ buffer->__routine = routine; ++ buffer->__arg = arg; ++ buffer->__prev = THREAD_GETMEM (self, cleanup); ++ ++ THREAD_SETMEM (self, cleanup, buffer); ++} ++strong_alias (_pthread_cleanup_push, __pthread_cleanup_push) ++ ++ ++void ++_pthread_cleanup_pop (struct _pthread_cleanup_buffer *buffer, int execute) ++{ ++ struct pthread *self __attribute ((unused)) = THREAD_SELF; ++ ++ THREAD_SETMEM (self, cleanup, buffer->__prev); ++ ++ /* If necessary call the cleanup routine after we removed the ++ current cleanup block from the list. */ ++ if (execute) ++ buffer->__routine (buffer->__arg); ++} ++strong_alias (_pthread_cleanup_pop, __pthread_cleanup_pop) +diff --git a/nptl_2_17/pthread_cond_broadcast_2_17.c b/nptl_2_17/pthread_cond_broadcast_2_17.c +new file mode 100644 +index 00000000..df39c99b +--- /dev/null ++++ b/nptl_2_17/pthread_cond_broadcast_2_17.c +@@ -0,0 +1,101 @@ ++/* Copyright (C) 2003-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Martin Schwidefsky , 2003. ++ ++ 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 ++ . */ ++ ++#include "kernel-features_2_17.h" ++#include "pthread_2_17.h" ++#include "pthreadP_2_17.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++ ++/* We do the following steps from __pthread_cond_signal in one critical ++ section: (1) signal all waiters in G1, (2) close G1 so that it can become ++ the new G2 and make G2 the new G1, and (3) signal all waiters in the new ++ G1. We don't need to do all these steps if there are no waiters in G1 ++ and/or G2. See __pthread_cond_signal for further details. */ ++int ++__pthread_cond_broadcast (pthread_cond_t *cond) ++{ ++ LIBC_PROBE (cond_broadcast, 1, cond); ++ ++ int pshared = (cond->__data.__mutex == (void *) ~0l) ++ ? LLL_SHARED : LLL_PRIVATE; ++ /* Make sure we are alone. */ ++ lll_lock (cond->__data.__lock, pshared); ++ ++ /* Are there any waiters to be woken? */ ++ if (cond->__data.__total_seq > cond->__data.__wakeup_seq) ++ ++ { ++ /* Yes. Mark them all as woken. */ ++ cond->__data.__wakeup_seq = cond->__data.__total_seq; ++ cond->__data.__woken_seq = cond->__data.__total_seq; ++ cond->__data.__futex = (unsigned int) cond->__data.__total_seq * 2; ++ int futex_val = cond->__data.__futex; ++ /* Signal that a broadcast happened. */ ++ ++cond->__data.__broadcast_seq; ++ ++ /* We are done. */ ++ lll_unlock (cond->__data.__lock, pshared); ++ ++ /* Wake everybody. */ ++ pthread_mutex_t *mut = (pthread_mutex_t *) cond->__data.__mutex; ++ ++ /* Do not use requeue for pshared condvars. */ ++ if (mut == (void *) ~0l ++ || PTHREAD_MUTEX_PSHARED (mut) & PTHREAD_MUTEX_PSHARED_BIT) ++ goto wake_all; ++ ++#if (defined lll_futex_cmp_requeue_pi \ ++ && defined __ASSUME_REQUEUE_PI) ++ if (USE_REQUEUE_PI (mut)) ++ { ++ if (lll_futex_cmp_requeue_pi (&cond->__data.__futex, 1, INT_MAX, ++ &mut->__data.__lock, futex_val, ++ LLL_PRIVATE) == 0) ++ return 0; ++ } ++ else ++#endif ++ /* lll_futex_requeue returns 0 for success and non-zero ++ for errors. */ ++ if (!__builtin_expect (lll_futex_requeue (&cond->__data.__futex, 1, ++ INT_MAX, &mut->__data.__lock, ++ futex_val, LLL_PRIVATE), 0)) ++ return 0; ++ ++wake_all: ++ lll_futex_wake (&cond->__data.__futex, INT_MAX, pshared); ++ return 0; ++ } ++ /* We are done. */ ++ lll_unlock (cond->__data.__lock, pshared); ++ ++ return 0; ++} ++ ++versioned_symbol (libpthread, __pthread_cond_broadcast, pthread_cond_broadcast, ++ GLIBC_2_3_2); +diff --git a/nptl_2_17/pthread_cond_destroy_2_17.c b/nptl_2_17/pthread_cond_destroy_2_17.c +new file mode 100644 +index 00000000..6342f471 +--- /dev/null ++++ b/nptl_2_17/pthread_cond_destroy_2_17.c +@@ -0,0 +1,86 @@ ++/* Copyright (C) 2002-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Ulrich Drepper , 2002. ++ ++ 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 ++ . */ ++ ++#include "pthreadP_2_17.h" ++#include ++#include ++#include ++#include ++int ++__pthread_cond_destroy (pthread_cond_t *cond) ++{ ++ int pshared = (cond->__data.__mutex == (void *) ~0l) ++ ? LLL_SHARED : LLL_PRIVATE; ++ ++ LIBC_PROBE (cond_destroy, 1, cond); ++ ++ /* Make sure we are alone. */ ++ lll_lock (cond->__data.__lock, pshared); ++ ++ if (cond->__data.__total_seq > cond->__data.__wakeup_seq) ++ { ++ /* If there are still some waiters which have not been ++ woken up, this is an application bug. */ ++ lll_unlock (cond->__data.__lock, pshared); ++ return EBUSY; ++ } ++ ++ /* Tell pthread_cond_*wait that this condvar is being destroyed. */ ++ cond->__data.__total_seq = -1ULL; ++ ++ /* If there are waiters which have been already signalled or ++ broadcasted, but still are using the pthread_cond_t structure, ++ pthread_cond_destroy needs to wait for them. */ ++ unsigned int nwaiters = cond->__data.__nwaiters; ++ ++ if (nwaiters >= (1 << COND_NWAITERS_SHIFT)) ++ ++ { ++ /* Wake everybody on the associated mutex in case there are ++ threads that have been requeued to it. ++ Without this, pthread_cond_destroy could block potentially ++ for a long time or forever, as it would depend on other ++ thread's using the mutex. ++ When all threads waiting on the mutex are woken up, pthread_cond_wait ++ only waits for threads to acquire and release the internal ++ condvar lock. */ ++ if (cond->__data.__mutex != NULL ++ && cond->__data.__mutex != (void *) ~0l) ++ { ++ pthread_mutex_t *mut = (pthread_mutex_t *) cond->__data.__mutex; ++ lll_futex_wake (&mut->__data.__lock, INT_MAX, ++ PTHREAD_MUTEX_PSHARED (mut)); ++ } ++ ++ do ++ { ++ lll_unlock (cond->__data.__lock, pshared); ++ ++ lll_futex_wait (&cond->__data.__nwaiters, nwaiters, pshared); ++ ++ lll_lock (cond->__data.__lock, pshared); ++ ++ nwaiters = cond->__data.__nwaiters; ++ } ++ while (nwaiters >= (1 << COND_NWAITERS_SHIFT)); ++ } ++ ++ return 0; ++} ++versioned_symbol (libpthread, __pthread_cond_destroy, ++ pthread_cond_destroy, GLIBC_2_3_2); +diff --git a/nptl_2_17/pthread_cond_init_2_17.c b/nptl_2_17/pthread_cond_init_2_17.c +new file mode 100644 +index 00000000..d590d1d0 +--- /dev/null ++++ b/nptl_2_17/pthread_cond_init_2_17.c +@@ -0,0 +1,49 @@ ++/* Copyright (C) 2002-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Ulrich Drepper , 2002. ++ ++ 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 ++ . */ ++ ++#include "pthreadP_2_17.h" ++#include ++#include ++ ++ ++int ++__pthread_cond_init (pthread_cond_t *cond, const pthread_condattr_t *cond_attr) ++{ ++ ASSERT_TYPE_SIZE (pthread_cond_t, __SIZEOF_PTHREAD_COND_T); ++ ++ struct pthread_condattr *icond_attr = (struct pthread_condattr *) cond_attr; ++ ++ cond->__data.__lock = LLL_LOCK_INITIALIZER; ++ cond->__data.__futex = 0; ++ cond->__data.__nwaiters = (icond_attr != NULL ++ ? ((icond_attr->value >> 1) & ((1 << COND_NWAITERS_SHIFT) - 1)) ++ : CLOCK_REALTIME); ++ cond->__data.__total_seq = 0; ++ cond->__data.__wakeup_seq = 0; ++ cond->__data.__woken_seq = 0; ++ cond->__data.__mutex = (icond_attr == NULL || (icond_attr->value & 1) == 0 ++ ? NULL : (void *) ~0l); ++ cond->__data.__broadcast_seq = 0; ++ ++ ++ LIBC_PROBE (cond_init, 2, cond, cond_attr); ++ ++ return 0; ++} ++versioned_symbol (libpthread, __pthread_cond_init, ++ pthread_cond_init, GLIBC_2_3_2); +diff --git a/nptl_2_17/pthread_cond_signal_2_17.c b/nptl_2_17/pthread_cond_signal_2_17.c +new file mode 100644 +index 00000000..e6f08ac8 +--- /dev/null ++++ b/nptl_2_17/pthread_cond_signal_2_17.c +@@ -0,0 +1,84 @@ ++/* Copyright (C) 2003-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Martin Schwidefsky , 2003. ++ ++ 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 ++ . */ ++ ++#include "kernel-features_2_17.h" ++#include "pthread_2_17.h" ++#include "pthreadP_2_17.h" ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++ ++int ++__pthread_cond_signal (pthread_cond_t *cond) ++{ ++ int pshared = (cond->__data.__mutex == (void *) ~0l) ++ ? LLL_SHARED : LLL_PRIVATE; ++ ++ LIBC_PROBE (cond_signal, 1, cond); ++ ++ /* Make sure we are alone. */ ++ lll_lock (cond->__data.__lock, pshared); ++ ++ /* Are there any waiters to be woken? */ ++ if (cond->__data.__total_seq > cond->__data.__wakeup_seq) ++ { ++ /* Yes. Mark one of them as woken. */ ++ ++cond->__data.__wakeup_seq; ++ ++cond->__data.__futex; ++ ++#if (defined lll_futex_cmp_requeue_pi \ ++ && defined __ASSUME_REQUEUE_PI) ++ pthread_mutex_t *mut = cond->__data.__mutex; ++ ++ if (USE_REQUEUE_PI (mut) ++ /* This can only really fail with a ENOSYS, since nobody can modify ++ futex while we have the cond_lock. */ ++ && lll_futex_cmp_requeue_pi (&cond->__data.__futex, 1, 0, ++ &mut->__data.__lock, ++ cond->__data.__futex, pshared) == 0) ++ { ++ lll_unlock (cond->__data.__lock, pshared); ++ return 0; ++ } ++ else ++#endif ++ /* Wake one. */ ++ if (! __builtin_expect (lll_futex_wake_unlock (&cond->__data.__futex, ++ 1, 1, ++ &cond->__data.__lock, ++ pshared), 0)) ++ return 0; ++ ++ /* Fallback if neither of them work. */ ++ lll_futex_wake (&cond->__data.__futex, 1, pshared); ++ } ++/* We are done. */ ++ lll_unlock (cond->__data.__lock, pshared); ++ ++ return 0; ++} ++ ++versioned_symbol (libpthread, __pthread_cond_signal, pthread_cond_signal, ++ GLIBC_2_3_2); +diff --git a/nptl_2_17/pthread_cond_wait_2_17.c b/nptl_2_17/pthread_cond_wait_2_17.c +new file mode 100644 +index 00000000..ff651a00 +--- /dev/null ++++ b/nptl_2_17/pthread_cond_wait_2_17.c +@@ -0,0 +1,329 @@ ++/* Copyright (C) 2003-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Martin Schwidefsky , 2003. ++ ++ 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 ++ . */ ++ ++#include "kernel-features_2_17.h" ++#include "pthread_2_17.h" ++#include "pthreadP_2_17.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++ ++struct _condvar_cleanup_buffer ++{ ++ int oldtype; ++ pthread_cond_t *cond; ++ pthread_mutex_t *mutex; ++ unsigned int bc_seq; ++}; ++ ++void ++__attribute__ ((visibility ("hidden"))) ++__condvar_cleanup (void *arg) ++{ ++ struct _condvar_cleanup_buffer *cbuffer = ++ (struct _condvar_cleanup_buffer *) arg; ++ unsigned int destroying; ++ int pshared = (cbuffer->cond->__data.__mutex == (void *) ~0l) ++ ? LLL_SHARED : LLL_PRIVATE; ++ ++ /* We are going to modify shared data. */ ++ lll_lock (cbuffer->cond->__data.__lock, pshared); ++ ++ if (cbuffer->bc_seq == cbuffer->cond->__data.__broadcast_seq) ++ { ++ /* This thread is not waiting anymore. Adjust the sequence counters ++ * appropriately. We do not increment WAKEUP_SEQ if this would ++ * bump it over the value of TOTAL_SEQ. This can happen if a thread ++ * was woken and then canceled. */ ++ if (cbuffer->cond->__data.__wakeup_seq ++ < cbuffer->cond->__data.__total_seq) ++ { ++ ++cbuffer->cond->__data.__wakeup_seq; ++ ++cbuffer->cond->__data.__futex; ++ } ++ ++cbuffer->cond->__data.__woken_seq; ++ } ++ ++ cbuffer->cond->__data.__nwaiters -= 1 << COND_NWAITERS_SHIFT; ++ ++ /* If pthread_cond_destroy was called on this variable already, ++ notify the pthread_cond_destroy caller all waiters have left ++ and it can be successfully destroyed. */ ++ destroying = 0; ++ if (cbuffer->cond->__data.__total_seq == -1ULL ++ && cbuffer->cond->__data.__nwaiters < (1 << COND_NWAITERS_SHIFT)) ++ { ++ lll_futex_wake (&cbuffer->cond->__data.__nwaiters, 1, pshared); ++ destroying = 1; ++ } ++ ++ /* We are done. */ ++ lll_unlock (cbuffer->cond->__data.__lock, pshared); ++ ++ /* Wake everybody to make sure no condvar signal gets lost. */ ++ if (! destroying) ++ lll_futex_wake (&cbuffer->cond->__data.__futex, INT_MAX, pshared); ++ ++ /* Get the mutex before returning unless asynchronous cancellation ++ is in effect. We don't try to get the mutex if we already own it. */ ++ if (!(USE_REQUEUE_PI (cbuffer->mutex)) ++ || ((cbuffer->mutex->__data.__lock & FUTEX_TID_MASK) ++ != THREAD_GETMEM (THREAD_SELF, tid))) ++ { ++ __pthread_mutex_cond_lock (cbuffer->mutex); ++ } ++ else ++ __pthread_mutex_cond_lock_adjust (cbuffer->mutex); ++} ++ ++static __always_inline int ++__pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, ++ clockid_t clockid, ++ const struct timespec *abstime) ++{ ++ struct _pthread_cleanup_buffer buffer; ++ struct _condvar_cleanup_buffer cbuffer; ++ int result = 0; ++ ++ int pshared = (cond->__data.__mutex == (void *) ~0l) ++ ? LLL_SHARED : LLL_PRIVATE; ++ ++ #if (defined lll_futex_wait_requeue_pi \ ++ && defined __ASSUME_REQUEUE_PI) ++ int pi_flag = 0; ++#endif ++ LIBC_PROBE (cond_wait, 2, cond, mutex); ++ /* clockid will already have been checked by ++ __pthread_cond_clockwait or pthread_condattr_setclock, or we ++ don't use it if abstime is NULL, so we don't need to check it ++ here. */ ++ /* Make sure we are alone. */ ++ lll_lock (cond->__data.__lock, pshared); ++ ++ /* Now we can release the mutex. */ ++ int err = __pthread_mutex_unlock_usercnt (mutex, 0); ++ if (__glibc_unlikely (err)) ++ { ++ lll_unlock (cond->__data.__lock, pshared); ++ return err; ++ } ++ ++ /* We have one new user of the condvar. */ ++ ++cond->__data.__total_seq; ++ ++cond->__data.__futex; ++ cond->__data.__nwaiters += 1 << COND_NWAITERS_SHIFT; ++ ++ /* Work around the fact that the kernel rejects negative timeout values ++ despite them being valid. */ ++ if (abstime != NULL && __glibc_unlikely (abstime->tv_sec < 0)) ++ goto timeout; ++ ++ /* Remember the mutex we are using here. If there is already a ++ different address store this is a bad user bug. Do not store ++ anything for pshared condvars. */ ++ if (cond->__data.__mutex != (void *) ~0l) ++ cond->__data.__mutex = mutex; ++ ++ /* Prepare structure passed to cancellation handler. */ ++ cbuffer.cond = cond; ++ cbuffer.mutex = mutex; ++ ++ /* Before we block we enable cancellation. Therefore we have to ++ install a cancellation handler. */ ++ __pthread_cleanup_push (&buffer, __condvar_cleanup, &cbuffer); ++ ++ /* The current values of the wakeup counter. The "woken" counter ++ must exceed this value. */ ++ unsigned long long int val; ++ unsigned long long int seq; ++ val = seq = cond->__data.__wakeup_seq; ++ /* Remember the broadcast counter. */ ++ cbuffer.bc_seq = cond->__data.__broadcast_seq; ++ ++ while (1) ++ { ++ unsigned int futex_val = cond->__data.__futex; ++ ++ /* Prepare to wait. Release the condvar futex. */ ++ lll_unlock (cond->__data.__lock, pshared); ++ ++ /* Enable asynchronous cancellation. Required by the standard. */ ++ cbuffer.oldtype = __pthread_enable_asynccancel (); ++ ++#if (defined lll_futex_wait_requeue_pi \ ++ && defined __ASSUME_REQUEUE_PI) ++ /* If pi_flag remained 1 then it means that we had the lock and the mutex ++ but a spurious waker raced ahead of us. Give back the mutex before ++ going into wait again. */ ++ if (pi_flag) ++ { ++ __pthread_mutex_cond_lock_adjust (mutex); ++ __pthread_mutex_unlock_usercnt (mutex, 0); ++ } ++ pi_flag = USE_REQUEUE_PI (mutex); ++ ++ if (pi_flag) ++ { ++ if (abstime == NULL) ++ { ++ err = lll_futex_wait_requeue_pi (&cond->__data.__futex, ++ futex_val, &mutex->__data.__lock, ++ pshared); ++ } ++ else ++ { ++ unsigned int clockbit = (clockid == CLOCK_REALTIME) ++ ? FUTEX_CLOCK_REALTIME : 0; ++ ++ err = lll_futex_timed_wait_requeue_pi (&cond->__data.__futex, ++ futex_val, abstime, clockbit, ++ &mutex->__data.__lock, ++ pshared); ++ } ++ pi_flag = (err == 0); ++ } ++ else ++#endif ++ /* Wait until woken by signal or broadcast. */ ++ { ++ if (abstime == NULL) ++ { ++ lll_futex_wait (&cond->__data.__futex, futex_val, pshared); ++ } ++ else ++ { ++ err = lll_futex_clock_wait_bitset (&cond->__data.__futex, futex_val, ++ clockid, abstime, pshared); ++ } ++ } ++ /* Disable asynchronous cancellation. */ ++ __pthread_disable_asynccancel (cbuffer.oldtype); ++ ++ /* We are going to look at shared data again, so get the lock. */ ++ lll_lock (cond->__data.__lock, pshared); ++ ++ /* If a broadcast happened, we are done. */ ++ if (cbuffer.bc_seq != cond->__data.__broadcast_seq) ++ goto bc_out; ++ ++ /* Check whether we are eligible for wakeup. */ ++ val = cond->__data.__wakeup_seq; ++ if (val != seq && cond->__data.__woken_seq != val) ++ break; ++ ++ /* Not woken yet. Maybe the time expired? */ ++ if (abstime != NULL && __glibc_unlikely (err == -ETIMEDOUT)) ++ { ++ timeout: ++ /* Yep. Adjust the counters. */ ++ ++cond->__data.__wakeup_seq; ++ ++cond->__data.__futex; ++ ++ /* The error value. */ ++ result = ETIMEDOUT; ++ break; ++ } ++ } ++ ++ /* Another thread woken up. */ ++ ++cond->__data.__woken_seq; ++ ++bc_out: ++ cond->__data.__nwaiters -= 1 << COND_NWAITERS_SHIFT; ++ ++ /* If pthread_cond_destroy was called on this variable already, ++ notify the pthread_cond_destroy caller all waiters have left ++ and it can be successfully destroyed. */ ++ if (cond->__data.__total_seq == -1ULL ++ && cond->__data.__nwaiters < (1 << COND_NWAITERS_SHIFT)) ++ lll_futex_wake (&cond->__data.__nwaiters, 1, pshared); ++ ++ /* We are done with the condvar. */ ++ lll_unlock (cond->__data.__lock, pshared); ++ ++ /* The cancellation handling is back to normal, remove the handler. */ ++ __pthread_cleanup_pop (&buffer, 0); ++ ++ /* Get the mutex before returning. */ ++#if (defined lll_futex_wait_requeue_pi \ ++ && defined __ASSUME_REQUEUE_PI) ++ if (pi_flag) ++ { ++ __pthread_mutex_cond_lock_adjust (mutex); ++ err = 0; ++ } ++ else ++#endif ++ err = __pthread_mutex_cond_lock (mutex); ++ return err ?: result; ++} ++/* See __pthread_cond_wait_common. */ ++int ++__pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) ++{ ++ /* clockid is unused when abstime is NULL. */ ++ return __pthread_cond_wait_common (cond, mutex, 0, NULL); ++} ++ ++/* See __pthread_cond_wait_common. */ ++int ++__pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, ++ const struct timespec *abstime) ++{ ++ /* Check parameter validity. This should also tell the compiler that ++ it can assume that abstime is not NULL. */ ++ if (abstime == NULL || abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) ++ return EINVAL; ++ ++ clockid_t clockid = cond->__data.__nwaiters & 1; ++ ++ return __pthread_cond_wait_common (cond, mutex, clockid, abstime); ++} ++ ++/* See __pthread_cond_wait_common. */ ++int ++__pthread_cond_clockwait (pthread_cond_t *cond, pthread_mutex_t *mutex, ++ clockid_t clockid, ++ const struct timespec *abstime) ++{ ++ /* Check parameter validity. This should also tell the compiler that ++ it can assume that abstime is not NULL. */ ++ if (abstime == NULL || abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) ++ return EINVAL; ++ ++ if (!futex_abstimed_supported_clockid (clockid)) ++ return EINVAL; ++ ++ return __pthread_cond_wait_common (cond, mutex, clockid, abstime); ++} ++ ++versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait, ++ GLIBC_2_3_2); ++versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait, ++ GLIBC_2_3_2); ++versioned_symbol (libpthread, __pthread_cond_clockwait, pthread_cond_clockwait, ++ GLIBC_2_34); +diff --git a/nptl_2_17/pthread_condattr_getclock_2_17.c b/nptl_2_17/pthread_condattr_getclock_2_17.c +new file mode 100644 +index 00000000..414a6856 +--- /dev/null ++++ b/nptl_2_17/pthread_condattr_getclock_2_17.c +@@ -0,0 +1,28 @@ ++/* Copyright (C) 2003-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Ulrich Drepper , 2003. ++ ++ 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 ++ . */ ++ ++#include "pthreadP_2_17.h" ++ ++ ++int ++pthread_condattr_getclock (const pthread_condattr_t *attr, clockid_t *clock_id) ++{ ++ *clock_id = (((((const struct pthread_condattr *) attr)->value) >> 1) ++ & ((1 << COND_NWAITERS_SHIFT) - 1)); ++ return 0; ++} +diff --git a/nptl_2_17/pthread_condattr_getpshared_2_17.c b/nptl_2_17/pthread_condattr_getpshared_2_17.c +new file mode 100644 +index 00000000..2b85506f +--- /dev/null ++++ b/nptl_2_17/pthread_condattr_getpshared_2_17.c +@@ -0,0 +1,28 @@ ++/* Copyright (C) 2002-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Ulrich Drepper , 2002. ++ ++ 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 ++ . */ ++ ++#include "pthreadP_2_17.h" ++ ++ ++int ++pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared) ++{ ++ *pshared = ((const struct pthread_condattr *) attr)->value & 1; ++ ++ return 0; ++} +diff --git a/nptl_2_17/pthread_condattr_init_2_17.c b/nptl_2_17/pthread_condattr_init_2_17.c +new file mode 100644 +index 00000000..c2765e96 +--- /dev/null ++++ b/nptl_2_17/pthread_condattr_init_2_17.c +@@ -0,0 +1,33 @@ ++/* Copyright (C) 2002-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Ulrich Drepper , 2002. ++ ++ 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 ++ . */ ++ ++#include "pthreadP_2_17.h" ++#include ++ ++ ++int ++__pthread_condattr_init (pthread_condattr_t *attr) ++{ ++ ASSERT_TYPE_SIZE (pthread_condattr_t, __SIZEOF_PTHREAD_CONDATTR_T); ++ ASSERT_PTHREAD_INTERNAL_SIZE (pthread_condattr_t, ++ struct pthread_condattr); ++ ++ memset (attr, '\0', sizeof (*attr)); ++ return 0; ++} ++strong_alias (__pthread_condattr_init, pthread_condattr_init) +diff --git a/nptl_2_17/pthread_condattr_setclock_2_17.c b/nptl_2_17/pthread_condattr_setclock_2_17.c +new file mode 100644 +index 00000000..69c64dcb +--- /dev/null ++++ b/nptl_2_17/pthread_condattr_setclock_2_17.c +@@ -0,0 +1,45 @@ ++/* Copyright (C) 2003-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Ulrich Drepper , 2003. ++ ++ 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 ++ . */ ++ ++#include "pthreadP_2_17.h" ++#include ++#include ++#include ++#include ++#include ++ ++ ++int ++pthread_condattr_setclock (pthread_condattr_t *attr, clockid_t clock_id) ++{ ++ /* Only a few clocks are allowed. */ ++ if (clock_id != CLOCK_MONOTONIC && clock_id != CLOCK_REALTIME) ++ /* If more clocks are allowed some day the storing of the clock ID ++ in the pthread_cond_t structure needs to be adjusted. */ ++ return EINVAL; ++ ++ /* Make sure the value fits in the bits we reserved. */ ++ assert (clock_id < (1 << COND_NWAITERS_SHIFT)); ++ ++ int *valuep = &((struct pthread_condattr *) attr)->value; ++ ++ *valuep = ((*valuep & ~(((1 << COND_NWAITERS_SHIFT) - 1) << 1)) ++ | (clock_id << 1)); ++ ++ return 0; ++} +diff --git a/nptl_2_17/pthread_mutex_cond_lock_2_17.c b/nptl_2_17/pthread_mutex_cond_lock_2_17.c +new file mode 100644 +index 00000000..87734543 +--- /dev/null ++++ b/nptl_2_17/pthread_mutex_cond_lock_2_17.c +@@ -0,0 +1,21 @@ ++#include ++ ++#define LLL_MUTEX_LOCK(mutex) \ ++ lll_cond_lock ((mutex)->__data.__lock, PTHREAD_MUTEX_PSHARED (mutex)) ++ ++/* Not actually elided so far. Needed? */ ++#define LLL_MUTEX_LOCK_ELISION(mutex) \ ++ ({ lll_cond_lock ((mutex)->__data.__lock, PTHREAD_MUTEX_PSHARED (mutex)); 0; }) ++ ++#define LLL_MUTEX_TRYLOCK(mutex) \ ++ lll_cond_trylock ((mutex)->__data.__lock) ++#define LLL_MUTEX_TRYLOCK_ELISION(mutex) LLL_MUTEX_TRYLOCK(mutex) ++ ++/* We need to assume that there are other threads blocked on the futex. ++ See __pthread_mutex_lock_full for further details. */ ++#define LLL_ROBUST_MUTEX_LOCK_MODIFIER FUTEX_WAITERS ++#define __pthread_mutex_lock __pthread_mutex_cond_lock ++#define __pthread_mutex_lock_full __pthread_mutex_cond_lock_full ++#define NO_INCR ++ ++#include +diff --git a/nptl_2_17/pthread_mutex_lock_2_17.c b/nptl_2_17/pthread_mutex_lock_2_17.c +new file mode 100644 +index 00000000..b08a2472 +--- /dev/null ++++ b/nptl_2_17/pthread_mutex_lock_2_17.c +@@ -0,0 +1,652 @@ ++/* Copyright (C) 2002-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Ulrich Drepper , 2002. ++ ++ 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 ++ . */ ++ ++#include "pthreadP_2_17.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#ifndef lll_lock_elision ++#define lll_lock_elision(lock, try_lock, private) ({ \ ++ lll_lock (lock, private); 0; }) ++#endif ++ ++#ifndef lll_trylock_elision ++#define lll_trylock_elision(a,t) lll_trylock(a) ++#endif ++ ++/* Some of the following definitions differ when pthread_mutex_cond_lock.c ++ includes this file. */ ++#ifndef LLL_MUTEX_LOCK ++/* lll_lock with single-thread optimization. */ ++static inline void ++lll_mutex_lock_optimized (pthread_mutex_t *mutex) ++{ ++ /* The single-threaded optimization is only valid for private ++ mutexes. For process-shared mutexes, the mutex could be in a ++ shared mapping, so synchronization with another process is needed ++ even without any threads. If the lock is already marked as ++ acquired, POSIX requires that pthread_mutex_lock deadlocks for ++ normal mutexes, so skip the optimization in that case as ++ well. */ ++ int private = PTHREAD_MUTEX_PSHARED (mutex); ++ if (private == LLL_PRIVATE && SINGLE_THREAD_P && mutex->__data.__lock == 0) ++ mutex->__data.__lock = 1; ++ else ++ lll_lock (mutex->__data.__lock, private); ++} ++# define LLL_MUTEX_LOCK(mutex) \ ++ lll_lock ((mutex)->__data.__lock, PTHREAD_MUTEX_PSHARED (mutex)) ++# define LLL_MUTEX_LOCK_OPTIMIZED(mutex) lll_mutex_lock_optimized (mutex) ++# define LLL_MUTEX_TRYLOCK(mutex) \ ++ lll_trylock ((mutex)->__data.__lock) ++# define LLL_ROBUST_MUTEX_LOCK_MODIFIER 0 ++# define LLL_MUTEX_LOCK_ELISION(mutex) \ ++ lll_lock_elision ((mutex)->__data.__lock, (mutex)->__data.__elision, \ ++ PTHREAD_MUTEX_PSHARED (mutex)) ++# define LLL_MUTEX_TRYLOCK_ELISION(mutex) \ ++ lll_trylock_elision((mutex)->__data.__lock, (mutex)->__data.__elision, \ ++ PTHREAD_MUTEX_PSHARED (mutex)) ++# define PTHREAD_MUTEX_LOCK ___pthread_mutex_lock ++# define PTHREAD_MUTEX_VERSIONS 1 ++#endif ++ ++static int __pthread_mutex_lock_full (pthread_mutex_t *mutex) ++ __attribute_noinline__; ++ ++int ++__pthread_mutex_lock (pthread_mutex_t *mutex) ++{ ++ /* See concurrency notes regarding mutex type which is loaded from __kind ++ in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */ ++ unsigned int type = PTHREAD_MUTEX_TYPE_ELISION (mutex); ++ ++ LIBC_PROBE (mutex_entry, 1, mutex); ++ ++ if (__builtin_expect (type & ~(PTHREAD_MUTEX_KIND_MASK_NP ++ | PTHREAD_MUTEX_ELISION_FLAGS_NP), 0)) ++ return __pthread_mutex_lock_full (mutex); ++ ++ if (__glibc_likely (type == PTHREAD_MUTEX_TIMED_NP)) ++ { ++ FORCE_ELISION (mutex, goto elision); ++ simple: ++ /* Normal mutex. */ ++ LLL_MUTEX_LOCK (mutex); ++ assert (mutex->__data.__owner == 0); ++ } ++#ifdef ENABLE_ELISION_SUPPORT ++ else if (__glibc_likely (type == PTHREAD_MUTEX_TIMED_ELISION_NP)) ++ { ++ elision: __attribute__((unused)) ++ /* This case can never happen on a system without elision, ++ as the mutex type initialization functions will not ++ allow to set the elision flags. */ ++ /* Don't record owner or users for elision case. This is a ++ tail call. */ ++ return LLL_MUTEX_LOCK_ELISION (mutex); ++ } ++#endif ++ else if (__builtin_expect (PTHREAD_MUTEX_TYPE (mutex) ++ == PTHREAD_MUTEX_RECURSIVE_NP, 1)) ++ { ++ /* Recursive mutex. */ ++ pid_t id = THREAD_GETMEM (THREAD_SELF, tid); ++ ++ /* Check whether we already hold the mutex. */ ++ if (mutex->__data.__owner == id) ++ { ++ /* Just bump the counter. */ ++ if (__glibc_unlikely (mutex->__data.__count + 1 == 0)) ++ /* Overflow of the counter. */ ++ return EAGAIN; ++ ++ ++mutex->__data.__count; ++ ++ return 0; ++ } ++ ++ /* We have to get the mutex. */ ++ LLL_MUTEX_LOCK (mutex); ++ ++ assert (mutex->__data.__owner == 0); ++ mutex->__data.__count = 1; ++ } ++ else if (__builtin_expect (PTHREAD_MUTEX_TYPE (mutex) ++ == PTHREAD_MUTEX_ADAPTIVE_NP, 1)) ++ { ++ if (! __is_smp) ++ goto simple; ++ ++ if (LLL_MUTEX_TRYLOCK (mutex) != 0) ++ { ++ int cnt = 0; ++ int max_cnt = MIN (MAX_ADAPTIVE_COUNT, ++ mutex->__data.__spins * 2 + 10); ++ do ++ { ++ if (cnt++ >= max_cnt) ++ { ++ LLL_MUTEX_LOCK (mutex); ++ break; ++ } ++ atomic_spin_nop (); ++ } ++ while (LLL_MUTEX_TRYLOCK (mutex) != 0); ++ ++ mutex->__data.__spins += (cnt - mutex->__data.__spins) / 8; ++ } ++ assert (mutex->__data.__owner == 0); ++ } ++ else ++ { ++ pid_t id = THREAD_GETMEM (THREAD_SELF, tid); ++ assert (PTHREAD_MUTEX_TYPE (mutex) == PTHREAD_MUTEX_ERRORCHECK_NP); ++ /* Check whether we already hold the mutex. */ ++ if (__glibc_unlikely (mutex->__data.__owner == id)) ++ return EDEADLK; ++ goto simple; ++ } ++ ++ pid_t id = THREAD_GETMEM (THREAD_SELF, tid); ++ ++ /* Record the ownership. */ ++ mutex->__data.__owner = id; ++#ifndef NO_INCR ++ ++mutex->__data.__nusers; ++#endif ++ ++ LIBC_PROBE (mutex_acquired, 1, mutex); ++ ++ return 0; ++} ++ ++static int ++__pthread_mutex_lock_full (pthread_mutex_t *mutex) ++{ ++ int oldval; ++ pid_t id = THREAD_GETMEM (THREAD_SELF, tid); ++ ++ switch (PTHREAD_MUTEX_TYPE (mutex)) ++ { ++ case PTHREAD_MUTEX_ROBUST_RECURSIVE_NP: ++ case PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP: ++ case PTHREAD_MUTEX_ROBUST_NORMAL_NP: ++ case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP: ++ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, ++ &mutex->__data.__list.__next); ++ /* We need to set op_pending before starting the operation. Also ++ see comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); ++ ++ oldval = mutex->__data.__lock; ++ /* This is set to FUTEX_WAITERS iff we might have shared the ++ FUTEX_WAITERS flag with other threads, and therefore need to keep it ++ set to avoid lost wake-ups. We have the same requirement in the ++ simple mutex algorithm. ++ We start with value zero for a normal mutex, and FUTEX_WAITERS if we ++ are building the special case mutexes for use from within condition ++ variables. */ ++ unsigned int assume_other_futex_waiters = LLL_ROBUST_MUTEX_LOCK_MODIFIER; ++ while (1) ++ { ++ /* Try to acquire the lock through a CAS from 0 (not acquired) to ++ our TID | assume_other_futex_waiters. */ ++ if (__glibc_likely (oldval == 0)) ++ { ++ oldval ++ = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, ++ id | assume_other_futex_waiters, 0); ++ if (__glibc_likely (oldval == 0)) ++ break; ++ } ++ ++ if ((oldval & FUTEX_OWNER_DIED) != 0) ++ { ++ /* The previous owner died. Try locking the mutex. */ ++ int newval = id; ++#ifdef NO_INCR ++ /* We are not taking assume_other_futex_waiters into accoount ++ here simply because we'll set FUTEX_WAITERS anyway. */ ++ newval |= FUTEX_WAITERS; ++#else ++ newval |= (oldval & FUTEX_WAITERS) | assume_other_futex_waiters; ++#endif ++ ++ newval ++ = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, ++ newval, oldval); ++ ++ if (newval != oldval) ++ { ++ oldval = newval; ++ continue; ++ } ++ ++ /* We got the mutex. */ ++ mutex->__data.__count = 1; ++ /* But it is inconsistent unless marked otherwise. */ ++ mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT; ++ ++ /* We must not enqueue the mutex before we have acquired it. ++ Also see comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); ++ ENQUEUE_MUTEX (mutex); ++ /* We need to clear op_pending after we enqueue the mutex. */ ++ __asm ("" ::: "memory"); ++ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); ++ ++ /* Note that we deliberately exit here. If we fall ++ through to the end of the function __nusers would be ++ incremented which is not correct because the old ++ owner has to be discounted. If we are not supposed ++ to increment __nusers we actually have to decrement ++ it here. */ ++#ifdef NO_INCR ++ --mutex->__data.__nusers; ++#endif ++ ++ return EOWNERDEAD; ++ } ++ ++ /* Check whether we already hold the mutex. */ ++ if (__glibc_unlikely ((oldval & FUTEX_TID_MASK) == id)) ++ { ++ int kind = PTHREAD_MUTEX_TYPE (mutex); ++ if (kind == PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP) ++ { ++ /* We do not need to ensure ordering wrt another memory ++ access. Also see comments at ENQUEUE_MUTEX. */ ++ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, ++ NULL); ++ return EDEADLK; ++ } ++ ++ if (kind == PTHREAD_MUTEX_ROBUST_RECURSIVE_NP) ++ { ++ /* We do not need to ensure ordering wrt another memory ++ access. */ ++ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, ++ NULL); ++ ++ /* Just bump the counter. */ ++ if (__glibc_unlikely (mutex->__data.__count + 1 == 0)) ++ /* Overflow of the counter. */ ++ return EAGAIN; ++ ++ ++mutex->__data.__count; ++ ++ return 0; ++ } ++ } ++ ++ /* We cannot acquire the mutex nor has its owner died. Thus, try ++ to block using futexes. Set FUTEX_WAITERS if necessary so that ++ other threads are aware that there are potentially threads ++ blocked on the futex. Restart if oldval changed in the ++ meantime. */ ++ if ((oldval & FUTEX_WAITERS) == 0) ++ { ++ if (atomic_compare_and_exchange_bool_acq (&mutex->__data.__lock, ++ oldval | FUTEX_WAITERS, ++ oldval) ++ != 0) ++ { ++ oldval = mutex->__data.__lock; ++ continue; ++ } ++ oldval |= FUTEX_WAITERS; ++ } ++ ++ /* It is now possible that we share the FUTEX_WAITERS flag with ++ another thread; therefore, update assume_other_futex_waiters so ++ that we do not forget about this when handling other cases ++ above and thus do not cause lost wake-ups. */ ++ assume_other_futex_waiters |= FUTEX_WAITERS; ++ ++ /* Block using the futex and reload current lock value. */ ++ lll_futex_wait (&mutex->__data.__lock, oldval, ++ PTHREAD_ROBUST_MUTEX_PSHARED (mutex)); ++ oldval = mutex->__data.__lock; ++ } ++ ++ /* We have acquired the mutex; check if it is still consistent. */ ++ if (__builtin_expect (mutex->__data.__owner ++ == PTHREAD_MUTEX_NOTRECOVERABLE, 0)) ++ { ++ /* This mutex is now not recoverable. */ ++ mutex->__data.__count = 0; ++ int private = PTHREAD_ROBUST_MUTEX_PSHARED (mutex); ++ lll_unlock (mutex->__data.__lock, private); ++ /* FIXME This violates the mutex destruction requirements. See ++ __pthread_mutex_unlock_full. */ ++ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); ++ return ENOTRECOVERABLE; ++ } ++ ++ mutex->__data.__count = 1; ++ /* We must not enqueue the mutex before we have acquired it. ++ Also see comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); ++ ENQUEUE_MUTEX (mutex); ++ /* We need to clear op_pending after we enqueue the mutex. */ ++ __asm ("" ::: "memory"); ++ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); ++ break; ++ ++ /* The PI support requires the Linux futex system call. If that's not ++ available, pthread_mutex_init should never have allowed the type to ++ be set. So it will get the default case for an invalid type. */ ++#ifdef __NR_futex ++ case PTHREAD_MUTEX_PI_RECURSIVE_NP: ++ case PTHREAD_MUTEX_PI_ERRORCHECK_NP: ++ case PTHREAD_MUTEX_PI_NORMAL_NP: ++ case PTHREAD_MUTEX_PI_ADAPTIVE_NP: ++ case PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP: ++ case PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP: ++ case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP: ++ case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP: ++ { ++ int kind, robust; ++ { ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind)); ++ kind = mutex_kind & PTHREAD_MUTEX_KIND_MASK_NP; ++ robust = mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; ++ } ++ ++ if (robust) ++ { ++ /* Note: robust PI futexes are signaled by setting bit 0. */ ++ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, ++ (void *) (((uintptr_t) &mutex->__data.__list.__next) ++ | 1)); ++ /* We need to set op_pending before starting the operation. Also ++ see comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); ++ } ++ ++ oldval = mutex->__data.__lock; ++ ++ /* Check whether we already hold the mutex. */ ++ if (__glibc_unlikely ((oldval & FUTEX_TID_MASK) == id)) ++ { ++ if (kind == PTHREAD_MUTEX_ERRORCHECK_NP) ++ { ++ /* We do not need to ensure ordering wrt another memory ++ access. */ ++ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); ++ return EDEADLK; ++ } ++ ++ if (kind == PTHREAD_MUTEX_RECURSIVE_NP) ++ { ++ /* We do not need to ensure ordering wrt another memory ++ access. */ ++ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); ++ ++ /* Just bump the counter. */ ++ if (__glibc_unlikely (mutex->__data.__count + 1 == 0)) ++ /* Overflow of the counter. */ ++ return EAGAIN; ++ ++ ++mutex->__data.__count; ++ ++ return 0; ++ } ++ } ++ ++ int newval = id; ++# ifdef NO_INCR ++ newval |= FUTEX_WAITERS; ++# endif ++ oldval = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, ++ newval, 0); ++ ++ if (oldval != 0) ++ { ++ /* The mutex is locked. The kernel will now take care of ++ everything. */ ++ int private = (robust ++ ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex) ++ : PTHREAD_MUTEX_PSHARED (mutex)); ++ INTERNAL_SYSCALL_DECL (__err); ++ int e = INTERNAL_SYSCALL (futex, 4, &mutex->__data.__lock, ++ __lll_private_flag (FUTEX_LOCK_PI, ++ private), 1, 0); ++ ++ if (INTERNAL_SYSCALL_ERROR_P (e) ++ && (INTERNAL_SYSCALL_ERRNO (e) == ESRCH ++ || INTERNAL_SYSCALL_ERRNO (e) == EDEADLK)) ++ { ++ assert (INTERNAL_SYSCALL_ERRNO (e) != EDEADLK ++ || (kind != PTHREAD_MUTEX_ERRORCHECK_NP ++ && kind != PTHREAD_MUTEX_RECURSIVE_NP)); ++ /* ESRCH can happen only for non-robust PI mutexes where ++ the owner of the lock died. */ ++ assert (INTERNAL_SYSCALL_ERRNO (e, __err) != ESRCH || !robust); ++ ++ /* Delay the thread indefinitely. */ ++ while (1) ++ __pause_nocancel (); ++ } ++ ++ oldval = mutex->__data.__lock; ++ ++ assert (robust || (oldval & FUTEX_OWNER_DIED) == 0); ++ } ++ ++ if (__glibc_unlikely (oldval & FUTEX_OWNER_DIED)) ++ { ++ atomic_and (&mutex->__data.__lock, ~FUTEX_OWNER_DIED); ++ ++ /* We got the mutex. */ ++ mutex->__data.__count = 1; ++ /* But it is inconsistent unless marked otherwise. */ ++ mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT; ++ ++ /* We must not enqueue the mutex before we have acquired it. ++ Also see comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); ++ ENQUEUE_MUTEX_PI (mutex); ++ /* We need to clear op_pending after we enqueue the mutex. */ ++ __asm ("" ::: "memory"); ++ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); ++ ++ /* Note that we deliberately exit here. If we fall ++ through to the end of the function __nusers would be ++ incremented which is not correct because the old owner ++ has to be discounted. If we are not supposed to ++ increment __nusers we actually have to decrement it here. */ ++# ifdef NO_INCR ++ --mutex->__data.__nusers; ++# endif ++ ++ return EOWNERDEAD; ++ } ++ ++ if (robust ++ && __builtin_expect (mutex->__data.__owner ++ == PTHREAD_MUTEX_NOTRECOVERABLE, 0)) ++ { ++ /* This mutex is now not recoverable. */ ++ mutex->__data.__count = 0; ++ ++ INTERNAL_SYSCALL_DECL (__err); ++ INTERNAL_SYSCALL (futex, 4, &mutex->__data.__lock, ++ __lll_private_flag (FUTEX_UNLOCK_PI, ++ PTHREAD_ROBUST_MUTEX_PSHARED (mutex)), ++ 0, 0); ++ ++ /* To the kernel, this will be visible after the kernel has ++ acquired the mutex in the syscall. */ ++ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); ++ return ENOTRECOVERABLE; ++ } ++ ++ mutex->__data.__count = 1; ++ if (robust) ++ { ++ /* We must not enqueue the mutex before we have acquired it. ++ Also see comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); ++ ENQUEUE_MUTEX_PI (mutex); ++ /* We need to clear op_pending after we enqueue the mutex. */ ++ __asm ("" ::: "memory"); ++ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); ++ } ++ } ++ break; ++#endif /* __NR_futex. */ ++ ++ case PTHREAD_MUTEX_PP_RECURSIVE_NP: ++ case PTHREAD_MUTEX_PP_ERRORCHECK_NP: ++ case PTHREAD_MUTEX_PP_NORMAL_NP: ++ case PTHREAD_MUTEX_PP_ADAPTIVE_NP: ++ { ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ int kind = atomic_load_relaxed (&(mutex->__data.__kind)) ++ & PTHREAD_MUTEX_KIND_MASK_NP; ++ ++ oldval = mutex->__data.__lock; ++ ++ /* Check whether we already hold the mutex. */ ++ if (mutex->__data.__owner == id) ++ { ++ if (kind == PTHREAD_MUTEX_ERRORCHECK_NP) ++ return EDEADLK; ++ ++ if (kind == PTHREAD_MUTEX_RECURSIVE_NP) ++ { ++ /* Just bump the counter. */ ++ if (__glibc_unlikely (mutex->__data.__count + 1 == 0)) ++ /* Overflow of the counter. */ ++ return EAGAIN; ++ ++ ++mutex->__data.__count; ++ ++ return 0; ++ } ++ } ++ ++ int oldprio = -1, ceilval; ++ do ++ { ++ int ceiling = (oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) ++ >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT; ++ ++ if (__pthread_current_priority () > ceiling) ++ { ++ if (oldprio != -1) ++ __pthread_tpp_change_priority (oldprio, -1); ++ return EINVAL; ++ } ++ ++ int retval = __pthread_tpp_change_priority (oldprio, ceiling); ++ if (retval) ++ return retval; ++ ++ ceilval = ceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT; ++ oldprio = ceiling; ++ ++ oldval ++ = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, ++#ifdef NO_INCR ++ ceilval | 2, ++#else ++ ceilval | 1, ++#endif ++ ceilval); ++ ++ if (oldval == ceilval) ++ break; ++ ++ do ++ { ++ oldval ++ = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, ++ ceilval | 2, ++ ceilval | 1); ++ ++ if ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval) ++ break; ++ ++ if (oldval != ceilval) ++ lll_futex_wait (&mutex->__data.__lock, ceilval | 2, ++ PTHREAD_MUTEX_PSHARED (mutex)); ++ } ++ while (atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, ++ ceilval | 2, ceilval) ++ != ceilval); ++ } ++ while ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval); ++ ++ assert (mutex->__data.__owner == 0); ++ mutex->__data.__count = 1; ++ } ++ break; ++ ++ default: ++ /* Correct code cannot set any other type. */ ++ return EINVAL; ++ } ++ ++ /* Record the ownership. */ ++ mutex->__data.__owner = id; ++#ifndef NO_INCR ++ ++mutex->__data.__nusers; ++#endif ++ ++ LIBC_PROBE (mutex_acquired, 1, mutex); ++ ++ return 0; ++} ++#ifndef __pthread_mutex_lock ++weak_alias (__pthread_mutex_lock, pthread_mutex_lock) ++hidden_def (__pthread_mutex_lock) ++#endif ++ ++ ++#ifdef NO_INCR ++void ++__pthread_mutex_cond_lock_adjust (pthread_mutex_t *mutex) ++{ ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind)); ++ assert ((mutex_kind & PTHREAD_MUTEX_PRIO_INHERIT_NP) != 0); ++ assert ((mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0); ++ assert ((mutex_kind & PTHREAD_MUTEX_PSHARED_BIT) == 0); ++ ++ /* Record the ownership. */ ++ pid_t id = THREAD_GETMEM (THREAD_SELF, tid); ++ mutex->__data.__owner = id; ++ ++ if (mutex_kind == PTHREAD_MUTEX_PI_RECURSIVE_NP) ++ ++mutex->__data.__count; ++} ++#endif +diff --git a/nptl_2_17/pthread_mutex_unlock_2_17.c b/nptl_2_17/pthread_mutex_unlock_2_17.c +new file mode 100644 +index 00000000..00729d32 +--- /dev/null ++++ b/nptl_2_17/pthread_mutex_unlock_2_17.c +@@ -0,0 +1,361 @@ ++/* Copyright (C) 2002-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Ulrich Drepper , 2002. ++ ++ 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 ++ . */ ++ ++#include "pthreadP_2_17.h" ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#ifndef lll_unlock_elision ++#define lll_unlock_elision(a,b,c) ({ lll_unlock (a,c); 0; }) ++#endif ++ ++static int ++__pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr) ++ __attribute_noinline__; ++ ++int ++attribute_hidden ++__pthread_mutex_unlock_usercnt (pthread_mutex_t *mutex, int decr) ++{ ++ /* See concurrency notes regarding mutex type which is loaded from __kind ++ in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */ ++ int type = PTHREAD_MUTEX_TYPE_ELISION (mutex); ++ if (__builtin_expect (type & ++ ~(PTHREAD_MUTEX_KIND_MASK_NP|PTHREAD_MUTEX_ELISION_FLAGS_NP), 0)) ++ return __pthread_mutex_unlock_full (mutex, decr); ++ ++ if (__builtin_expect (type, PTHREAD_MUTEX_TIMED_NP) ++ == PTHREAD_MUTEX_TIMED_NP) ++ { ++ /* Always reset the owner field. */ ++ normal: ++ mutex->__data.__owner = 0; ++ if (decr) ++ /* One less user. */ ++ --mutex->__data.__nusers; ++ ++ /* Unlock. */ ++ lll_unlock (mutex->__data.__lock, PTHREAD_MUTEX_PSHARED (mutex)); ++ ++ LIBC_PROBE (mutex_release, 1, mutex); ++ ++ return 0; ++ } ++ else if (__glibc_likely (type == PTHREAD_MUTEX_TIMED_ELISION_NP)) ++ { ++ /* Don't reset the owner/users fields for elision. */ ++ return lll_unlock_elision (mutex->__data.__lock, mutex->__data.__elision, ++ PTHREAD_MUTEX_PSHARED (mutex)); ++ } ++ else if (__builtin_expect (PTHREAD_MUTEX_TYPE (mutex) ++ == PTHREAD_MUTEX_RECURSIVE_NP, 1)) ++ { ++ /* Recursive mutex. */ ++ if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)) ++ return EPERM; ++ ++ if (--mutex->__data.__count != 0) ++ /* We still hold the mutex. */ ++ return 0; ++ goto normal; ++ } ++ else if (__builtin_expect (PTHREAD_MUTEX_TYPE (mutex) ++ == PTHREAD_MUTEX_ADAPTIVE_NP, 1)) ++ goto normal; ++ else ++ { ++ /* Error checking mutex. */ ++ assert (type == PTHREAD_MUTEX_ERRORCHECK_NP); ++ if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid) ++ || ! lll_islocked (mutex->__data.__lock)) ++ return EPERM; ++ goto normal; ++ } ++} ++ ++ ++static int ++__pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr) ++{ ++ int newowner = 0; ++ int private; ++ ++ switch (PTHREAD_MUTEX_TYPE (mutex)) ++ { ++ case PTHREAD_MUTEX_ROBUST_RECURSIVE_NP: ++ /* Recursive mutex. */ ++ if ((mutex->__data.__lock & FUTEX_TID_MASK) ++ == THREAD_GETMEM (THREAD_SELF, tid) ++ && __builtin_expect (mutex->__data.__owner ++ == PTHREAD_MUTEX_INCONSISTENT, 0)) ++ { ++ if (--mutex->__data.__count != 0) ++ /* We still hold the mutex. */ ++ return ENOTRECOVERABLE; ++ ++ goto notrecoverable; ++ } ++ ++ if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)) ++ return EPERM; ++ ++ if (--mutex->__data.__count != 0) ++ /* We still hold the mutex. */ ++ return 0; ++ ++ goto robust; ++ ++ case PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP: ++ case PTHREAD_MUTEX_ROBUST_NORMAL_NP: ++ case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP: ++ if ((mutex->__data.__lock & FUTEX_TID_MASK) ++ != THREAD_GETMEM (THREAD_SELF, tid) ++ || ! lll_islocked (mutex->__data.__lock)) ++ return EPERM; ++ ++ /* If the previous owner died and the caller did not succeed in ++ making the state consistent, mark the mutex as unrecoverable ++ and make all waiters. */ ++ if (__builtin_expect (mutex->__data.__owner ++ == PTHREAD_MUTEX_INCONSISTENT, 0)) ++ notrecoverable: ++ newowner = PTHREAD_MUTEX_NOTRECOVERABLE; ++ ++ robust: ++ /* Remove mutex from the list. */ ++ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, ++ &mutex->__data.__list.__next); ++ /* We must set op_pending before we dequeue the mutex. Also see ++ comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); ++ DEQUEUE_MUTEX (mutex); ++ ++ mutex->__data.__owner = newowner; ++ if (decr) ++ /* One less user. */ ++ --mutex->__data.__nusers; ++ ++ /* Unlock by setting the lock to 0 (not acquired); if the lock had ++ FUTEX_WAITERS set previously, then wake any waiters. ++ The unlock operation must be the last access to the mutex to not ++ violate the mutex destruction requirements (see __lll_unlock). */ ++ private = PTHREAD_ROBUST_MUTEX_PSHARED (mutex); ++ if (__glibc_unlikely ((atomic_exchange_rel (&mutex->__data.__lock, 0) ++ & FUTEX_WAITERS) != 0)) ++ lll_futex_wake (&mutex->__data.__lock, 1, private); ++ ++ /* We must clear op_pending after we release the mutex. ++ FIXME However, this violates the mutex destruction requirements ++ because another thread could acquire the mutex, destroy it, and ++ reuse the memory for something else; then, if this thread crashes, ++ and the memory happens to have a value equal to the TID, the kernel ++ will believe it is still related to the mutex (which has been ++ destroyed already) and will modify some other random object. */ ++ __asm ("" ::: "memory"); ++ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); ++ break; ++ ++ /* The PI support requires the Linux futex system call. If that's not ++ available, pthread_mutex_init should never have allowed the type to ++ be set. So it will get the default case for an invalid type. */ ++#ifdef __NR_futex ++ case PTHREAD_MUTEX_PI_RECURSIVE_NP: ++ /* Recursive mutex. */ ++ if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)) ++ return EPERM; ++ ++ if (--mutex->__data.__count != 0) ++ /* We still hold the mutex. */ ++ return 0; ++ goto continue_pi_non_robust; ++ ++ case PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP: ++ /* Recursive mutex. */ ++ if ((mutex->__data.__lock & FUTEX_TID_MASK) ++ == THREAD_GETMEM (THREAD_SELF, tid) ++ && __builtin_expect (mutex->__data.__owner ++ == PTHREAD_MUTEX_INCONSISTENT, 0)) ++ { ++ if (--mutex->__data.__count != 0) ++ /* We still hold the mutex. */ ++ return ENOTRECOVERABLE; ++ ++ goto pi_notrecoverable; ++ } ++ ++ if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)) ++ return EPERM; ++ ++ if (--mutex->__data.__count != 0) ++ /* We still hold the mutex. */ ++ return 0; ++ ++ goto continue_pi_robust; ++ ++ case PTHREAD_MUTEX_PI_ERRORCHECK_NP: ++ case PTHREAD_MUTEX_PI_NORMAL_NP: ++ case PTHREAD_MUTEX_PI_ADAPTIVE_NP: ++ case PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP: ++ case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP: ++ case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP: ++ if ((mutex->__data.__lock & FUTEX_TID_MASK) ++ != THREAD_GETMEM (THREAD_SELF, tid) ++ || ! lll_islocked (mutex->__data.__lock)) ++ return EPERM; ++ ++ /* If the previous owner died and the caller did not succeed in ++ making the state consistent, mark the mutex as unrecoverable ++ and make all waiters. */ ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ if ((atomic_load_relaxed (&(mutex->__data.__kind)) ++ & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0 ++ && __builtin_expect (mutex->__data.__owner ++ == PTHREAD_MUTEX_INCONSISTENT, 0)) ++ pi_notrecoverable: ++ newowner = PTHREAD_MUTEX_NOTRECOVERABLE; ++ ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ if ((atomic_load_relaxed (&(mutex->__data.__kind)) ++ & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0) ++ { ++ continue_pi_robust: ++ /* Remove mutex from the list. ++ Note: robust PI futexes are signaled by setting bit 0. */ ++ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, ++ (void *) (((uintptr_t) &mutex->__data.__list.__next) ++ | 1)); ++ /* We must set op_pending before we dequeue the mutex. Also see ++ comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); ++ DEQUEUE_MUTEX (mutex); ++ } ++ ++ continue_pi_non_robust: ++ mutex->__data.__owner = newowner; ++ if (decr) ++ /* One less user. */ ++ --mutex->__data.__nusers; ++ ++ /* Unlock. Load all necessary mutex data before releasing the mutex ++ to not violate the mutex destruction requirements (see ++ lll_unlock). */ ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ int robust = atomic_load_relaxed (&(mutex->__data.__kind)) ++ & PTHREAD_MUTEX_ROBUST_NORMAL_NP; ++ private = (robust ++ ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex) ++ : PTHREAD_MUTEX_PSHARED (mutex)); ++ /* Unlock the mutex using a CAS unless there are futex waiters or our ++ TID is not the value of __lock anymore, in which case we let the ++ kernel take care of the situation. Use release MO in the CAS to ++ synchronize with acquire MO in lock acquisitions. */ ++ int l = atomic_load_relaxed (&mutex->__data.__lock); ++ do ++ { ++ if (((l & FUTEX_WAITERS) != 0) ++ || (l != THREAD_GETMEM (THREAD_SELF, tid))) ++ { ++ INTERNAL_SYSCALL_DECL (__err); ++ INTERNAL_SYSCALL (futex, 2, &mutex->__data.__lock, ++ __lll_private_flag (FUTEX_UNLOCK_PI, private)); ++ break; ++ } ++ } ++ while (!atomic_compare_exchange_weak_release (&mutex->__data.__lock, ++ &l, 0)); ++ ++ /* This happens after the kernel releases the mutex but violates the ++ mutex destruction requirements; see comments in the code handling ++ PTHREAD_MUTEX_ROBUST_NORMAL_NP. */ ++ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); ++ break; ++#endif /* __NR_futex. */ ++ ++ case PTHREAD_MUTEX_PP_RECURSIVE_NP: ++ /* Recursive mutex. */ ++ if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)) ++ return EPERM; ++ ++ if (--mutex->__data.__count != 0) ++ /* We still hold the mutex. */ ++ return 0; ++ goto pp; ++ ++ case PTHREAD_MUTEX_PP_ERRORCHECK_NP: ++ /* Error checking mutex. */ ++ if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid) ++ || (mutex->__data.__lock & ~ PTHREAD_MUTEX_PRIO_CEILING_MASK) == 0) ++ return EPERM; ++ /* FALLTHROUGH */ ++ ++ case PTHREAD_MUTEX_PP_NORMAL_NP: ++ case PTHREAD_MUTEX_PP_ADAPTIVE_NP: ++ /* Always reset the owner field. */ ++ pp: ++ mutex->__data.__owner = 0; ++ ++ if (decr) ++ /* One less user. */ ++ --mutex->__data.__nusers; ++ ++ /* Unlock. Use release MO in the CAS to synchronize with acquire MO in ++ lock acquisitions. */ ++ int newval; ++ int oldval = atomic_load_relaxed (&mutex->__data.__lock); ++ do ++ { ++ newval = oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK; ++ } ++ while (!atomic_compare_exchange_weak_release (&mutex->__data.__lock, ++ &oldval, newval)); ++ ++ if ((oldval & ~PTHREAD_MUTEX_PRIO_CEILING_MASK) > 1) ++ lll_futex_wake (&mutex->__data.__lock, 1, ++ PTHREAD_MUTEX_PSHARED (mutex)); ++ ++ int oldprio = newval >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT; ++ ++ LIBC_PROBE (mutex_release, 1, mutex); ++ ++ return __pthread_tpp_change_priority (oldprio, -1); ++ ++ default: ++ /* Correct code cannot set any other type. */ ++ return EINVAL; ++ } ++ ++ LIBC_PROBE (mutex_release, 1, mutex); ++ return 0; ++} ++ ++ ++int ++__pthread_mutex_unlock (pthread_mutex_t *mutex) ++{ ++ return __pthread_mutex_unlock_usercnt (mutex, 1); ++} ++weak_alias (__pthread_mutex_unlock, pthread_mutex_unlock) ++hidden_def (__pthread_mutex_unlock) +diff --git a/nptl_2_17/tpp_2_17.c b/nptl_2_17/tpp_2_17.c +new file mode 100644 +index 00000000..45fff81a +--- /dev/null ++++ b/nptl_2_17/tpp_2_17.c +@@ -0,0 +1,195 @@ ++/* Thread Priority Protect helpers. ++ Copyright (C) 2006-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Jakub Jelinek , 2006. ++ ++ 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 ++ . */ ++ ++#include "pthreadP_2_17.h" ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++int __sched_fifo_min_prio = -1; ++int __sched_fifo_max_prio = -1; ++ ++/* We only want to initialize __sched_fifo_min_prio and __sched_fifo_max_prio ++ once. The standard solution would be similar to pthread_once, but then ++ readers would need to use an acquire fence. In this specific case, ++ initialization is comprised of just idempotent writes to two variables ++ that have an initial value of -1. Therefore, we can treat each variable as ++ a separate, at-least-once initialized value. This enables using just ++ relaxed MO loads and stores, but requires that consumers check for ++ initialization of each value that is to be used; see ++ __pthread_tpp_change_priority for an example. ++ */ ++void ++__init_sched_fifo_prio (void) ++{ ++ atomic_store_relaxed (&__sched_fifo_max_prio, ++ __sched_get_priority_max (SCHED_FIFO)); ++ atomic_store_relaxed (&__sched_fifo_min_prio, ++ __sched_get_priority_min (SCHED_FIFO)); ++} ++ ++int ++__pthread_tpp_change_priority (int previous_prio, int new_prio) ++{ ++ struct pthread *self = THREAD_SELF; ++ struct priority_protection_data *tpp = THREAD_GETMEM (self, tpp); ++ int fifo_min_prio = atomic_load_relaxed (&__sched_fifo_min_prio); ++ int fifo_max_prio = atomic_load_relaxed (&__sched_fifo_max_prio); ++ ++ if (tpp == NULL) ++ { ++ /* See __init_sched_fifo_prio. We need both the min and max prio, ++ so need to check both, and run initialization if either one is ++ not initialized. The memory model's write-read coherence rule ++ makes this work. */ ++ if (fifo_min_prio == -1 || fifo_max_prio == -1) ++ { ++ __init_sched_fifo_prio (); ++ fifo_min_prio = atomic_load_relaxed (&__sched_fifo_min_prio); ++ fifo_max_prio = atomic_load_relaxed (&__sched_fifo_max_prio); ++ } ++ ++ size_t size = sizeof *tpp; ++ size += (fifo_max_prio - fifo_min_prio + 1) ++ * sizeof (tpp->priomap[0]); ++ tpp = calloc (size, 1); ++ if (tpp == NULL) ++ return ENOMEM; ++ tpp->priomax = fifo_min_prio - 1; ++ THREAD_SETMEM (self, tpp, tpp); ++ } ++ ++ assert (new_prio == -1 ++ || (new_prio >= fifo_min_prio ++ && new_prio <= fifo_max_prio)); ++ assert (previous_prio == -1 ++ || (previous_prio >= fifo_min_prio ++ && previous_prio <= fifo_max_prio)); ++ ++ int priomax = tpp->priomax; ++ int newpriomax = priomax; ++ if (new_prio != -1) ++ { ++ if (tpp->priomap[new_prio - fifo_min_prio] + 1 == 0) ++ return EAGAIN; ++ ++tpp->priomap[new_prio - fifo_min_prio]; ++ if (new_prio > priomax) ++ newpriomax = new_prio; ++ } ++ ++ if (previous_prio != -1) ++ { ++ if (--tpp->priomap[previous_prio - fifo_min_prio] == 0 ++ && priomax == previous_prio ++ && previous_prio > new_prio) ++ { ++ int i; ++ for (i = previous_prio - 1; i >= fifo_min_prio; --i) ++ if (tpp->priomap[i - fifo_min_prio]) ++ break; ++ newpriomax = i; ++ } ++ } ++ ++ if (priomax == newpriomax) ++ return 0; ++ ++ /* See CREATE THREAD NOTES in nptl/pthread_create.c. */ ++ lll_lock (self->lock, LLL_PRIVATE); ++ ++ tpp->priomax = newpriomax; ++ ++ int result = 0; ++ ++ if ((self->flags & ATTR_FLAG_SCHED_SET) == 0) ++ { ++ if (__sched_getparam (self->tid, &self->schedparam) != 0) ++ result = errno; ++ else ++ self->flags |= ATTR_FLAG_SCHED_SET; ++ } ++ ++ if ((self->flags & ATTR_FLAG_POLICY_SET) == 0) ++ { ++ self->schedpolicy = __sched_getscheduler (self->tid); ++ if (self->schedpolicy == -1) ++ result = errno; ++ else ++ self->flags |= ATTR_FLAG_POLICY_SET; ++ } ++ ++ if (result == 0) ++ { ++ struct sched_param sp = self->schedparam; ++ if (sp.sched_priority < newpriomax || sp.sched_priority < priomax) ++ { ++ if (sp.sched_priority < newpriomax) ++ sp.sched_priority = newpriomax; ++ ++ if (__sched_setscheduler (self->tid, self->schedpolicy, &sp) < 0) ++ result = errno; ++ } ++ } ++ ++ lll_unlock (self->lock, LLL_PRIVATE); ++ ++ return result; ++} ++ ++int ++__pthread_current_priority (void) ++{ ++ struct pthread *self = THREAD_SELF; ++ if ((self->flags & (ATTR_FLAG_POLICY_SET | ATTR_FLAG_SCHED_SET)) ++ == (ATTR_FLAG_POLICY_SET | ATTR_FLAG_SCHED_SET)) ++ return self->schedparam.sched_priority; ++ ++ int result = 0; ++ ++ /* See CREATE THREAD NOTES in nptl/pthread_create.c. */ ++ lll_lock (self->lock, LLL_PRIVATE); ++ ++ if ((self->flags & ATTR_FLAG_SCHED_SET) == 0) ++ { ++ if (__sched_getparam (self->tid, &self->schedparam) != 0) ++ result = -1; ++ else ++ self->flags |= ATTR_FLAG_SCHED_SET; ++ } ++ ++ if ((self->flags & ATTR_FLAG_POLICY_SET) == 0) ++ { ++ self->schedpolicy = __sched_getscheduler (self->tid); ++ if (self->schedpolicy == -1) ++ result = -1; ++ else ++ self->flags |= ATTR_FLAG_POLICY_SET; ++ } ++ ++ if (result != -1) ++ result = self->schedparam.sched_priority; ++ ++ lll_unlock (self->lock, LLL_PRIVATE); ++ ++ return result; ++} +diff --git a/nptl_2_17/vars_2_17.c b/nptl_2_17/vars_2_17.c +new file mode 100644 +index 00000000..ae60c0f8 +--- /dev/null ++++ b/nptl_2_17/vars_2_17.c +@@ -0,0 +1,43 @@ ++/* Copyright (C) 2004-2018 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 ++ . */ ++ ++#include "pthreadP_2_17.h" ++#include ++#include ++#include ++ ++/* Default thread attributes for the case when the user does not ++ provide any. */ ++struct pthread_attr __default_pthread_attr attribute_hidden; ++ ++/* Mutex protecting __default_pthread_attr. */ ++int __default_pthread_attr_lock = LLL_LOCK_INITIALIZER; ++ ++/* Flag whether the machine is SMP or not. */ ++int __is_smp attribute_hidden; ++ ++#ifndef TLS_MULTIPLE_THREADS_IN_TCB ++/* Variable set to a nonzero value either if more than one thread runs or ran, ++ or if a single-threaded process is trying to cancel itself. See ++ nptl/descr.h for more context on the single-threaded process case. */ ++int __pthread_multiple_threads attribute_hidden; ++#endif ++ ++/* Table of the key information. */ ++struct pthread_key_struct __pthread_keys[PTHREAD_KEYS_MAX] ++ __attribute__ ((nocommon)); ++hidden_data_def (__pthread_keys) +-- +2.30.0 + diff --git a/0001-elf-dynamic-linker-load-shared-object-use-hugepage-a.patch b/0001-elf-dynamic-linker-load-shared-object-use-hugepage-a.patch new file mode 100644 index 0000000000000000000000000000000000000000..3a561e1cc83c65bc50759adc3c7e37fc357c1c53 --- /dev/null +++ b/0001-elf-dynamic-linker-load-shared-object-use-hugepage-a.patch @@ -0,0 +1,1179 @@ +From 28a9a4123b8a7494c0b5e70fd943fa7aa4f64fe8 Mon Sep 17 00:00:00 2001 +From: Lv Ying +Date: Mon, 7 Mar 2022 03:28:33 +0000 +Subject: [PATCH 1/3] elf: dynamic linker load shared object use hugepage as + much as possible + +This patch provides environment variables HUGEPAGE_PROBE and LD_HUGEPAGE_LIB +to enable load shared object use hugepage. + +When load shared object, ld.so first to map text PT_LOAD segment into 2MB +hugepage area. And then, load the neighbor PT_LOAD segment use 2MB hugepage +as much as possible. This means: +* PT_LOAD segment's mapstart_va is 2MB aligned, howerver its maplenth is + less than 2MB, fallback to 4KB page +* PT_LOAD segment's mapstart_va is 2MB aligned, and its maplenth is larger + than 2MB, the first 2MB aligned area use 2MB hugepage, the end area (if it exists) use 4KB area +* PT_LOAD segment's mapstart_va is not 2MB aligned, alignup this address + to 2MB aligned address mapstart_align, if its maplenth is less than + mapstart_align - mapstart_va, or maplenth - (mapstart_align - mapstart_va), fallback to 4KB hugepage +* PT_LOAD segment's mapstart_va is not 2MB aligned, maplenth - (mapstart_align - mapstart_va) + is still larger than 2MB, first map (mapstart_align - mapstart_va) as 4KB page + then map 2MB aligned area as hugepage, the end area (if it exists) use 4KB area +--- + config.h.in | 2 + + configure | 20 ++ + configure.ac | 11 + + elf/Makefile | 8 + + elf/dl-environ.c | 11 + + elf/dl-load.c | 38 +++ + elf/dl-load.h | 16 + + elf/dl-map-segments-hugepage.h | 593 +++++++++++++++++++++++++++++++++ + elf/elf.h | 2 + + elf/hugepageedit.c | 169 ++++++++++ + elf/rtld.c | 64 ++++ + sysdeps/generic/ldsodefs.h | 6 +- + 12 files changed, 939 insertions(+), 1 deletion(-) + create mode 100644 elf/dl-map-segments-hugepage.h + create mode 100644 elf/hugepageedit.c + +diff --git a/config.h.in b/config.h.in +index db6402cd..13101496 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -277,6 +277,8 @@ + /* Define if static PIE is supported. */ + #undef SUPPORT_STATIC_PIE + ++#undef HUGEPAGE_SHARED_LIB ++ + /* Define if static PIE is enabled. */ + #define ENABLE_STATIC_PIE 0 + +diff --git a/configure b/configure +index 7272fbf6..43993923 100755 +--- a/configure ++++ b/configure +@@ -670,6 +670,7 @@ stack_protector + libc_cv_ssp + libc_cv_with_fp + base_machine ++enable_hugepage_shared_library + have_tunables + build_pt_chown + build_nscd +@@ -791,6 +792,7 @@ enable_pt_chown + enable_tunables + enable_mathvec + enable_cet ++enable_hugepage_shared_library + enable_scv + with_cpu + ' +@@ -1464,6 +1466,9 @@ Optional Features: + depends on architecture] + --enable-cet enable Intel Control-flow Enforcement Technology + (CET), x86 only ++ --enable-hugepage-shared-library ++ enable shared library use huge page to decrease TLB ++ miss, x86_64 aarch64 only + --disable-scv syscalls will not use scv instruction, even if the + kernel supports it, powerpc only + +@@ -3830,6 +3835,21 @@ if test "$use_scv" != "no"; then : + + fi + ++# Check whether --enable-hugepage-shared-library was given. ++if test "${enable_hugepage_shared_library+set}" = set; then : ++ enableval=$enable_hugepage_shared_library; enable_hugepage_shared_library=$enableval ++else ++ enable_hugepage_shared_library=no ++fi ++ ++ ++config_vars="$config_vars ++enable-hugepage-shared-library = $enable_hugepage_shared_library" ++if test "$enable_hugepage_shared_library" = yes; then ++ $as_echo "#define HUGEPAGE_SHARED_LIB 1" >>confdefs.h ++ ++fi ++ + # We keep the original values in `$config_*' and never modify them, so we + # can write them unchanged into config.make. Everything else uses + # $machine, $vendor, and $os, and changes them whenever convenient. +diff --git a/configure.ac b/configure.ac +index af47cd51..27a48338 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -478,6 +478,17 @@ AC_ARG_ENABLE([scv], + + AS_IF([[test "$use_scv" != "no"]],[AC_DEFINE(USE_PPC_SCV)]) + ++AC_ARG_ENABLE([hugepage-shared-library], ++ AC_HELP_STRING([--enable-hugepage-shared-library], ++ [enable shared library use huge page to decrease TLB miss, x86_64 aarch64 only]), ++ [enable_hugepage_shared_library=$enableval], ++ [enable_hugepage_shared_library=no]) ++ ++LIBC_CONFIG_VAR([enable-hugepage-shared-library], [$enable_hugepage_shared_library]) ++if test "$enable_hugepage_shared_library" = yes; then ++ AC_DEFINE(HUGEPAGE_SHARED_LIB) ++fi ++ + # We keep the original values in `$config_*' and never modify them, so we + # can write them unchanged into config.make. Everything else uses + # $machine, $vendor, and $os, and changes them whenever convenient. +diff --git a/elf/Makefile b/elf/Makefile +index 48bb4703..1574574d 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -207,6 +207,14 @@ others-extras = $(ldconfig-modules) + endif + endif + ++ifeq (yes,$(enable-hugepage-shared-library)) ++others += hugepageedit ++others-pie += hugepageedit ++install-bin += hugepageedit ++ ++$(objpfx)hugepageedit: $(objpfx)hugepageedit.o ++endif ++ + # To find xmalloc.c and xstrdup.c + vpath %.c ../locale/programs + +diff --git a/elf/dl-environ.c b/elf/dl-environ.c +index 31c1c09f..ac70c9ab 100644 +--- a/elf/dl-environ.c ++++ b/elf/dl-environ.c +@@ -31,6 +31,17 @@ _dl_next_ld_env_entry (char ***position) + + while (*current != NULL) + { ++#ifdef HUGEPAGE_SHARED_LIB ++ #define LEN_HUGEPAGE_PROBE (sizeof("HUGEPAGE_PROBE") - 1) ++ if (memcmp (*current, "HUGEPAGE_PROBE", LEN_HUGEPAGE_PROBE) == 0) ++ { ++ result = *current; ++ ++ /* Save current position for next visit. */ ++ *position = ++current; ++ break; ++ } ++#endif + if (__builtin_expect ((*current)[0] == 'L', 0) + && (*current)[1] == 'D' && (*current)[2] == '_') + { +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 0976977f..57d5754e 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -73,6 +73,9 @@ struct filebuf + #include + #include + #include ++#ifdef HUGEPAGE_SHARED_LIB ++#include ++#endif + + #include + #if BYTE_ORDER == BIG_ENDIAN +@@ -1131,6 +1134,9 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + size_t nloadcmds = 0; + bool has_holes = false; + bool empty_dynamic = false; ++#ifdef HUGEPAGE_SHARED_LIB ++ bool use_hugepage = false; ++#endif + + /* The struct is initialized to zero so this is not necessary: + l->l_ld = 0; +@@ -1188,6 +1194,11 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + if (nloadcmds > 1 && c[-1].mapend != c->mapstart) + has_holes = true; + ++#ifdef HUGEPAGE_SHARED_LIB ++ if (ph->p_flags & PF_HUGEPAGE) ++ use_hugepage = true; ++#endif ++ + /* Optimize a common case. */ + #if (PF_R | PF_W | PF_X) == 7 && (PROT_READ | PROT_WRITE | PROT_EXEC) == 7 + c->prot = (PF_TO_PROT +@@ -1278,12 +1289,39 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + /* Length of the sections to be loaded. */ + maplength = loadcmds[nloadcmds - 1].allocend - loadcmds[0].mapstart; + ++#ifdef HUGEPAGE_SHARED_LIB ++#define ERRSTRING_BUF_LEN 1024 ++ int hp_errcode = 0; ++ char hp_buf[ERRSTRING_BUF_LEN]; ++ if ((GLRO(dl_debug_mask) & DL_HUGEPAGE_LIB_LARGE_IN_FLAG) || ++ ((GLRO(dl_debug_mask) & DL_HUGEPAGE_PROBE_FLAG) && use_hugepage)) ++ { ++ errstring = _dl_map_segments_largein (l, fd, header, type, loadcmds, nloadcmds, ++ maplength, has_holes); ++ if (__glibc_unlikely (errstring != NULL)) ++ { ++ hp_errcode = errno; ++ /* __strerror_r will set hp_buf last character '\0', hp_buf will not overflow */ ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf ("_dl_map_segments_largein: %s, %s\n", errstring, ++ hp_errcode ? __strerror_r (hp_errcode, hp_buf, sizeof hp_buf) : ""); ++ goto fallback; ++ } ++ } ++ else ++ { ++ fallback: ++ errstring = _dl_map_segments (l, fd, header, type, loadcmds, nloadcmds, ++ maplength, has_holes, loader); ++ } ++#else + /* Now process the load commands and map segments into memory. + This is responsible for filling in: + l_map_start, l_map_end, l_addr, l_contiguous, l_text_end, l_phdr + */ + errstring = _dl_map_segments (l, fd, header, type, loadcmds, nloadcmds, + maplength, has_holes, loader); ++#endif + if (__glibc_unlikely (errstring != NULL)) + { + /* Mappings can be in an inconsistent state: avoid unmap. */ +diff --git a/elf/dl-load.h b/elf/dl-load.h +index e329d49a..d3f69466 100644 +--- a/elf/dl-load.h ++++ b/elf/dl-load.h +@@ -131,5 +131,21 @@ static const char *_dl_map_segments (struct link_map *l, int fd, + #define DL_MAP_SEGMENTS_ERROR_MAP_ZERO_FILL \ + N_("cannot map zero-fill pages") + ++#ifdef HUGEPAGE_SHARED_LIB ++#define DL_MAP_SEGMENTS_ERROR_TYPE \ ++ N_("cannot map Non shared object file in hugepage") ++#define DL_MAP_SEGMENTS_ERROR_READ_SEGMENT \ ++ N_("failed to read shared object file") ++#define DL_MAP_SEGMENTS_ERROR_ARRANGE \ ++ N_("shared object's PT_LOAD segment in wrong arrange") ++#define DL_MAP_SEGMENTS_ERROR_MAP_HOLE_FILL \ ++ N_("failed to mmap shared object's hole part of PT_LOAD") ++#define DL_MAP_RESERVED_HUGEPAGE_AREA_ERROR \ ++ N_("failed to map reserved 2MB contiguous hugepage va space") ++#define DL_FIND_EXEC_SEGMENT_ERROR \ ++ N_("fail to find exec prot segment") ++#define DL_MAP_SEGMENT_ERROR_EXTRA_SIZE \ ++ N_("wrong segment extra size") ++#endif + + #endif /* dl-load.h */ +diff --git a/elf/dl-map-segments-hugepage.h b/elf/dl-map-segments-hugepage.h +new file mode 100644 +index 00000000..cd7b6d79 +--- /dev/null ++++ b/elf/dl-map-segments-hugepage.h +@@ -0,0 +1,593 @@ ++/* Map a shared object's segments into hugepage. Generic version. ++ Copyright (C) 1995-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 ++ . */ ++ ++#include ++ ++#define SHFIT_2MB 21 ++#define SIZE_2MB 0x200000 ++#define MASK_2MB 0x1FFFFF ++#define THRESHOLD 16 ++ ++/* ++ * Find the first PT_LOAD segment with execute permission ++ */ ++static __always_inline const struct loadcmd * ++_find_exec_segment(const struct loadcmd loadcmds[], size_t nloadcmds) ++{ ++ const struct loadcmd *c = loadcmds; ++ ++ while (c < &loadcmds[nloadcmds]) ++ { ++ if (c->prot & PROT_EXEC) ++ return c; ++ c++; ++ } ++ return NULL; ++} ++ ++static __always_inline void * ++__mmap_reserved_area(const struct loadcmd loadcmds[], size_t nloadcmds, ++ size_t *maparealen) ++{ ++ const struct loadcmd * c = loadcmds; ++ *maparealen = 0; ++ ++ while (c < &loadcmds[nloadcmds]) ++ { ++ *maparealen += ALIGN_UP((c->mapend > c->allocend ? c->mapend : c->allocend), SIZE_2MB) - ++ ALIGN_DOWN(c->mapstart, SIZE_2MB); ++ c++; ++ } ++ ++ /* ++ * Get 2MB aligned contiguous va space ++ * This va space can not be munmap in case of multi thread dlopen concurrently ++ */ ++ void *map_area_start = __mmap(0, *maparealen, PROT_NONE, ++ MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB|(SHFIT_2MB << MAP_HUGE_SHIFT), -1, 0); ++ if (__glibc_unlikely (map_area_start == MAP_FAILED)) ++ return MAP_FAILED; ++ ++ /* ++ * Remap 2MB aligned contiguous va space into 4KB contiguous va space ++ * to avoid the tedious work of splitting hugepage into 4KB page ++ */ ++ if (__glibc_unlikely(__mmap(map_area_start, *maparealen, PROT_NONE, ++ MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0) ++ == MAP_FAILED)) ++ { ++ goto unmap_reserved_area; ++ } ++ return map_area_start; ++ ++unmap_reserved_area: ++ __munmap(map_area_start, *maparealen); ++ return MAP_FAILED; ++} ++ ++static __always_inline size_t ++_get_relro_len(struct link_map *l, const struct loadcmd *c) ++{ ++ size_t relro_len = 0; ++ if (c->mapstart == ALIGN_DOWN (l->l_relro_addr, GLRO(dl_pagesize))) ++ { ++ relro_len = ALIGN_DOWN(l->l_relro_addr + l->l_relro_size, GLRO(dl_pagesize)) - ++ ALIGN_DOWN(l->l_relro_addr, GLRO(dl_pagesize)); ++ } ++ return relro_len; ++} ++ ++/* ++ * the alignment stands for the size of page which is to be cleared to zero ++ */ ++static __always_inline const char * ++_zero_tail_page(const struct loadcmd *c, ElfW(Addr) zero, ElfW(Addr) zeropage, ++ size_t alignment) ++{ ++ if (__glibc_unlikely ((c->prot & PROT_WRITE) == 0)) ++ { ++ /* Dag nab it. */ ++ if (__mprotect ((caddr_t) ALIGN_DOWN(zero, alignment), alignment, ++ c->prot|PROT_WRITE) < 0) ++ return DL_MAP_SEGMENTS_ERROR_MPROTECT; ++ } ++ memset ((void *) zero, '\0', zeropage - zero); ++ if (__glibc_unlikely ((c->prot & PROT_WRITE) == 0)) ++ __mprotect ((caddr_t) ALIGN_DOWN(zero, alignment), alignment, c->prot); ++ return NULL; ++} ++ ++static __always_inline const char * ++_mmap_remain_zero_page(ElfW(Addr) zeropage, ElfW(Addr) zeroend, int prot) ++{ ++ ElfW(Addr) hp_start = ALIGN_UP(zeropage, SIZE_2MB); ++ size_t len = 0, mod = 0; ++ caddr_t mapat; ++ ++ if (zeroend > hp_start && zeroend - hp_start >= SIZE_2MB) ++ { ++ len = zeroend - hp_start; ++ mod = len % SIZE_2MB; ++ } ++ else ++ hp_start = 0; ++ ++ if (hp_start == 0) ++ { ++ mapat = __mmap((caddr_t) zeropage, zeroend - zeropage, prot, ++ MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0); ++ if (__glibc_unlikely (mapat == MAP_FAILED)) ++ return DL_MAP_SEGMENTS_ERROR_MAP_ZERO_FILL; ++ return NULL; ++ } ++ ++ if (hp_start - zeropage > 0) ++ { ++ mapat = __mmap((caddr_t) zeropage, hp_start - zeropage, ++ prot, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0); ++ if (__glibc_unlikely (mapat == MAP_FAILED)) ++ return DL_MAP_SEGMENTS_ERROR_MAP_ZERO_FILL; ++ } ++ ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("\t\t\t=> mmap anonymous hugepage: [%lx-%lx)\n", hp_start, hp_start + len - mod); ++ mapat = __mmap((caddr_t) hp_start, len - mod, prot, ++ MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB|(SHFIT_2MB << MAP_HUGE_SHIFT), ++ -1, 0); ++ if (__glibc_unlikely (mapat == MAP_FAILED)) ++ return DL_MAP_SEGMENTS_ERROR_MAP_ZERO_FILL; ++ ++ if (mod > 0) ++ { ++ mapat =__mmap((caddr_t)(hp_start + len - mod), mod, prot, ++ MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0); ++ if (__glibc_unlikely (mapat == MAP_FAILED)) ++ return DL_MAP_SEGMENTS_ERROR_MAP_ZERO_FILL; ++ } ++ ++ return NULL; ++} ++ ++/* ++ * memsz_len records the remain memsiz part ++ */ ++static __always_inline const char * ++_mmap_segment_memsz(struct link_map *l, const struct loadcmd * c, ++ ElfW(Addr) mapstart, size_t extra_len, size_t *memsz_len) ++{ ++ const char * errstring = NULL; ++ ++ /* Extra zero pages should appear at the end of this segment, ++ after the data mapped from the file. */ ++ ElfW(Addr) zero, zeroend, zeropage; ++ ++ zero = mapstart + c->dataend - c->mapstart; ++ zeroend = mapstart + c->allocend - c->mapstart; ++ zeropage = ALIGN_UP(zero, GLRO(dl_pagesize)); ++ size_t alignment = GLRO(dl_pagesize); ++ *memsz_len = 0; ++ ++ /* ++ * no matter what the extra space consists of: ++ * 1. all the extra space is initialized data area (MemSiz > FileSiz) ++ * 2. initialized data area and hole ++ * 3. all the extra space is hole (MemSiz == FileSiz) ++ * ++ * the extra space just needs to be set zero, for the initialized data area, it's ++ * initialized to zero; for the hole area, it's initialized to invalid instruction ++ */ ++ if (extra_len > 0) ++ { ++ if (__glibc_unlikely(zeropage == ALIGN_UP(zero, SIZE_2MB) || ++ zeropage + extra_len != ALIGN_UP(zero, SIZE_2MB))) ++ return DL_MAP_SEGMENT_ERROR_EXTRA_SIZE; ++ ++ zeropage = ALIGN_UP(zero, SIZE_2MB); ++ alignment = SIZE_2MB; ++ } ++ else ++ { ++ /* ++ * extra_len = 0, _mmap_segment_filesz just mmap segment's FileSiz part, ++ * here, it needs to zero tail page [FileSiz end, tail page end) part ++ */ ++ if (c->allocend <= c->dataend) ++ return NULL; ++ ++ if (ALIGN_UP(zero, GLRO(dl_pagesize)) == ALIGN_UP(zero, SIZE_2MB) && ++ (zeropage - (mapstart + _get_relro_len(l, c)) >= SIZE_2MB)) ++ { ++ alignment = SIZE_2MB; ++ } ++ ++ if (zeroend < zeropage) ++ zeropage = zeroend; ++ } ++ ++ if (zeropage > zero) ++ { ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("\t\tzero tail page [%lx-%lx) which contains hole area length: 0x%lx\n", ++ zero, zeropage, zeropage > ALIGN_UP(zero, GLRO(dl_pagesize)) ? ++ zeropage - ALIGN_UP(zero, GLRO(dl_pagesize)) : 0); ++ errstring = _zero_tail_page(c, zero, zeropage, alignment); ++ if (errstring != NULL) ++ return errstring; ++ } ++ ++ if (zeroend > zeropage) ++ { ++ *memsz_len = ALIGN_UP(zeroend, GLRO(dl_pagesize)) - zeropage; ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("\t\tzero remain page [%lx-%lx)\n", zeropage, zeroend); ++ errstring = _mmap_remain_zero_page(zeropage, zeroend, c->prot); ++ } ++ return errstring; ++} ++ ++/* ++ * mmap as fixed addr, if the middle part is 2MB aligned, ++ * this part should be mmaped in 2MB aligned, else in 4KB aligned ++ * 2MB hugepage area should be set with correct permissions, no need to remap ++ */ ++static __always_inline const char * ++_mmap_segment_filesz(struct link_map *l, const struct loadcmd *c, ElfW(Addr) mapstart, ++ size_t extra_len, int fd) ++{ ++ void *map_addr = 0; ++ ++ size_t relro_len = _get_relro_len(l, c); ++ if (relro_len > 0) ++ { ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("\t\tmmap relro: [%lx-%lx)\n", mapstart, mapstart + relro_len); ++ /* ++ * relro part must be mapped as normal page size to avoid ++ * _dl_protect_relro failure ++ */ ++ map_addr = __mmap((void *)mapstart, relro_len, c->prot, ++ MAP_PRIVATE|MAP_FIXED|MAP_FILE, ++ fd, c->mapoff); ++ if (__glibc_unlikely (map_addr == MAP_FAILED)) ++ return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT; ++ ++ mapstart += relro_len; ++ } ++ ++ size_t prev_map_len = ALIGN_UP(mapstart, SIZE_2MB) - mapstart; ++ size_t len = (c->mapend + extra_len) - (c->mapstart + relro_len); ++ if (len <= prev_map_len || len - prev_map_len < SIZE_2MB) ++ { ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("\t\tmmap all: [%lx-%lx), which includes prev_map_len(0x%lx)\n", ++ mapstart, mapstart + len, prev_map_len); ++ mapstart = (ElfW(Addr))__mmap((void *)mapstart, len, c->prot, ++ MAP_PRIVATE|MAP_FIXED|MAP_FILE, ++ fd, c->mapoff + relro_len); ++ if (__glibc_unlikely ((void *)mapstart == MAP_FAILED)) ++ return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT; ++ return NULL; ++ } ++ ++ if (prev_map_len > 0) ++ { ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("\t\tmmap prev_map_len: [%lx-%lx)\n", ++ mapstart, mapstart + prev_map_len); ++ mapstart = (ElfW(Addr))__mmap((void *)mapstart, prev_map_len, c->prot, ++ MAP_PRIVATE|MAP_FIXED|MAP_FILE, ++ fd, c->mapoff + relro_len); ++ if (__glibc_unlikely ((void *)mapstart == MAP_FAILED)) ++ return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT; ++ ++ map_addr = map_addr == 0 ? (void *)mapstart : map_addr; ++ mapstart += prev_map_len; ++ len -= prev_map_len; ++ } ++ ++ size_t mod = len % SIZE_2MB; ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("\t\tmmap hugepage: [%lx-%lx)\n", mapstart, mapstart + len - mod); ++ mapstart = (ElfW(Addr))__mmap((void *)mapstart, len - mod, c->prot, ++ MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB|(SHFIT_2MB << MAP_HUGE_SHIFT), ++ -1, 0); ++ if (__glibc_unlikely ((void *)mapstart == MAP_FAILED)) ++ return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT; ++ ++ if ((c->prot & PROT_WRITE) == 0 && __mprotect((void *)mapstart, len - mod, c->prot | PROT_WRITE) < 0) ++ { ++ return DL_MAP_SEGMENTS_ERROR_MPROTECT; ++ } ++ ++ /* Read the segment contents from the file. */ ++ size_t file_len = (size_t)(c->dataend - c->mapstart) <= prev_map_len + relro_len ? 0 : ++ (size_t)(c->dataend - c->mapstart) - prev_map_len - relro_len; ++ if (file_len > 0) ++ { ++ lseek(fd, c->mapoff + relro_len + prev_map_len, SEEK_SET); ++ if ( __read(fd, (void *)mapstart, file_len < len - mod ? file_len : len - mod) < 0) ++ return DL_MAP_SEGMENTS_ERROR_READ_SEGMENT; ++ } ++ ++ if ((c->prot & PROT_WRITE) == 0 && __mprotect((void *)mapstart, len - mod, c->prot) < 0) ++ { ++ return DL_MAP_SEGMENTS_ERROR_MPROTECT; ++ } ++ ++ map_addr = map_addr == 0 ? (void *)mapstart : map_addr; ++ mapstart += len - mod; ++ ++ if (__glibc_unlikely (extra_len > 0 && mod > 0)) ++ return DL_MAP_SEGMENT_ERROR_EXTRA_SIZE; ++ ++ if (mod > 0 && __glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("\t\tmmap tail part: [%lx-%lx)\n", mapstart, mapstart + mod); ++ if (mod > 0 && __mmap((void *)mapstart, mod, c->prot, ++ MAP_PRIVATE|MAP_FIXED|MAP_FILE, ++ fd, c->mapoff + relro_len + prev_map_len + len - mod) ++ == MAP_FAILED) ++ { ++ return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT; ++ } ++ return NULL; ++} ++ ++/* ++ * mmap segment filesz tail part only covers the very first part of hugepage, ++ * if the size of this tail part reach the threshold, map the tail part in hugepage ++ * ++ * The tail part must be calculated by mapend, because this is file mmaping, ++ * if tail part is calculated by allocend, it will mmap invalid data in file ++ * s: mapstart mp: mapend ac: allocend ++ * 1. [s, mp) can not cover the tail hugepage start, mp, s, ac are all in same hugepage, no extra space ++ * s mp ac ++ * | | | ++ * |--------|--------| ++ * ++ * 2. [s, mp) can not cover the tail hugepage start, ac is in the behind hugepage, no extra space ++ * s mp ac ++ * | | | ++ * |--------|--------|--------| ++ * ++ * 3. [s, mp) covers the tail hugepage start, mp and the ac in the same hugepage, ++ * if (ac - ALIGN_DOWN(mp, SIZE_2MB) < threshold, no extra space; else extra space ++ * [mp, ALIGN_UP(mp, SIZE_2MB) which contains initialized data area and hole ++ * if ac == mp, the extra space only contains hole ++ * s1 s2 mp ac ++ * | | | | ++ * |--------|--------|--------| ++ * ++ * 4. [s, mp) covers the tail hugepage start, ac is in the behind hugepage, ++ * the extra space is [mp, ALIGN_UP(mp, SIZE_2MB) which only contains initialized data area ++ * s1 s2 mp ac ++ * | | | | ++ * |--------|--------|--------|--------|--------| ++ * ++ * 5. if mp is 2MB aligned, no matter [s, mp) covers the tail hugepage start or not, ++ * no extra area ++ * s1 s2 s3 mp ac ++ * | | | | | ++ * |--------|--------|--------|--------|--------| ++ * ++ * there are a few points to note: ++ * 1. the extra part shold not overlap with the next segment ++ * 2. PT_LOAD segment which contains relro section should update mapstart ++ */ ++static __always_inline size_t ++_extra_mmap(struct link_map *l, const struct loadcmd loadcmds[], size_t nloadcmds, ++ const struct loadcmd *c, ElfW(Addr) mapstart) ++{ ++ ElfW(Addr) mapend = mapstart + (c->mapend - c->mapstart); ++ ElfW(Addr) hugepage = ALIGN_DOWN(mapend, SIZE_2MB); ++ size_t relro_len = _get_relro_len(l, c); ++ mapstart += relro_len; ++ ++ /* ++ * 1. mapend is 2MB aligned ++ * 2. [mapstart, mapend) does not cover the tail hugepage start ++ */ ++ if (mapend == ALIGN_UP(mapend, SIZE_2MB) || mapstart > hugepage) ++ return 0; ++ ++ /* the initialized data area end in the tail hugepage */ ++ ElfW(Addr) end = (mapstart - relro_len) + ALIGN_UP(c->allocend - c->mapstart, GLRO(dl_pagesize)) >= ++ ALIGN_UP(mapend, SIZE_2MB) ? ALIGN_UP(mapend, SIZE_2MB) : ++ (mapstart - relro_len) + ALIGN_UP(c->allocend - c->mapstart, GLRO(dl_pagesize)); ++ ++ size_t extra_len = ALIGN_UP(mapend, SIZE_2MB) - mapend; ++ if ((end - hugepage < THRESHOLD * GLRO(dl_pagesize)) || ((c < loadcmds + (nloadcmds - 1)) && ++ (ALIGN_UP(mapend, SIZE_2MB) > (mapstart - relro_len) + c[1].mapstart - c->mapstart))) ++ { ++ extra_len = 0; ++ } ++ ++ return extra_len; ++} ++ ++/* ++ * PT_LOAD segment is described by p_filesz and p_memsz. ++ * The bytes from the file are mapped to the beginning of the memory segment. ++ * If the segment’s memory size (p_memsz) is larger than the file size (p_filesz), ++ * the extra bytes are defined to hold the value 0 and to follow the segment’s ++ * initialized area ++ */ ++static __always_inline const char * ++_mmap_segment(struct link_map *l, const struct loadcmd loadcmds[], size_t nloadcmds, ++ const struct loadcmd *c, ElfW(Addr) mapstart, int fd, size_t *mapseglen) ++{ ++ const char * errstring = NULL; ++ size_t extra_len = _extra_mmap(l, loadcmds, nloadcmds, c, mapstart); ++ size_t memsz_len = 0; ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("\t%s(0x%lx): extra_len = 0x%lx\n\t{\n", __func__, ++ (unsigned long)c, extra_len); ++ ++ errstring = _mmap_segment_filesz(l, c, mapstart, extra_len, fd); ++ if (__glibc_unlikely (errstring != NULL)) ++ return errstring; ++ errstring = _mmap_segment_memsz(l, c, mapstart, extra_len, &memsz_len); ++ if (__glibc_unlikely (errstring != NULL)) ++ return errstring; ++ ++ *mapseglen = c->mapend - c->mapstart + extra_len + memsz_len; ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("\t} => mapseglen = 0x%lx, memsz_len = 0x%lx\n", *mapseglen, memsz_len); ++ return NULL; ++} ++ ++static __always_inline void * ++_mmap_hole(const struct loadcmd *current, const struct loadcmd *next, ++ ElfW(Addr) mapstart, size_t mapseglen, int fd) ++{ ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("\tmmap hole area:[%lx-%lx)\n", mapstart + mapseglen, ++ mapstart + (next->mapstart - current->mapstart)); ++ return __mmap((void *)(mapstart + mapseglen), ++ next->mapstart - (current->mapstart + mapseglen), ++ PROT_NONE, MAP_FILE|MAP_PRIVATE|MAP_FIXED, ++ fd, current->mapoff + mapseglen); ++} ++ ++static __always_inline const char * ++_dl_map_segments_largein (struct link_map *l, int fd, ++ const ElfW(Ehdr) *header, int type, ++ const struct loadcmd loadcmds[], size_t nloadcmds, ++ const size_t maplength, bool has_holes) ++{ ++ if (__glibc_unlikely (type != ET_DYN)) ++ return DL_MAP_SEGMENTS_ERROR_TYPE; ++ ++ const char *errstring = NULL; ++ const struct loadcmd *text = _find_exec_segment(loadcmds, nloadcmds); ++ if (__glibc_unlikely (text == NULL)) ++ return DL_FIND_EXEC_SEGMENT_ERROR; ++ ++ size_t maparealen; ++ void *map_area_start = __mmap_reserved_area(loadcmds, nloadcmds, &maparealen); ++ if (__glibc_unlikely (map_area_start == MAP_FAILED)) ++ return DL_MAP_RESERVED_HUGEPAGE_AREA_ERROR; ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("reserved area:[%lx-%lx)\n", ++ (unsigned long)map_area_start, (unsigned long)map_area_start + maparealen); ++ ++ /* First to mmap text segment */ ++ const struct loadcmd * c = loadcmds; ++ ElfW(Addr) text_addr = ALIGN_UP((ElfW(Addr))map_area_start + (text->mapstart - c->mapstart), SIZE_2MB); ++ size_t mapseglen; ++ errstring = _mmap_segment(l, loadcmds, nloadcmds, text, text_addr, fd, &mapseglen); ++ if (__glibc_unlikely(errstring != NULL)) ++ goto unmap_reserved_area; ++ ++ const struct loadcmd *prev = text; ++ c = text + 1; ++ ElfW(Addr) map_addr = text_addr; ++ while (c < &loadcmds[nloadcmds]) ++ { ++ if (prev->mapstart + mapseglen > c->mapstart || c->mapstart < prev->mapstart) ++ { ++ errstring = DL_MAP_SEGMENTS_ERROR_ARRANGE; ++ goto unmap_reserved_area; ++ } ++ ++ if (prev->mapstart + mapseglen < c->mapstart && ++ _mmap_hole(prev, c, map_addr, mapseglen, fd) == MAP_FAILED) ++ { ++ errstring = DL_MAP_SEGMENTS_ERROR_MAP_HOLE_FILL; ++ goto unmap_reserved_area; ++ } ++ ++ map_addr += c->mapstart - prev->mapstart; ++ errstring = _mmap_segment(l, loadcmds, nloadcmds, c, map_addr, fd, &mapseglen); ++ if (__glibc_unlikely(errstring != NULL)) ++ goto unmap_reserved_area; ++ prev = c; ++ ++c; ++ } ++ ElfW(Addr) l_map_end = map_addr + mapseglen; ++ ++ /* search for the first segment */ ++ prev = text; ++ c = text - 1; ++ map_addr = text_addr; ++ while (c >= loadcmds) ++ { ++ if (prev->mapstart < c->mapstart) ++ { ++ errstring = DL_MAP_SEGMENTS_ERROR_ARRANGE; ++ goto unmap_reserved_area; ++ } ++ ++ map_addr -= prev->mapstart - c->mapstart; ++ errstring = _mmap_segment(l, loadcmds, nloadcmds, c, map_addr, fd, &mapseglen); ++ if (__glibc_unlikely(errstring != NULL)) ++ goto unmap_reserved_area; ++ ++ if (c->mapstart + mapseglen > prev->mapstart) ++ { ++ errstring = DL_MAP_SEGMENTS_ERROR_ARRANGE; ++ goto unmap_reserved_area; ++ } ++ ++ if (c->mapstart + mapseglen < prev->mapstart && ++ _mmap_hole(c, prev, map_addr, mapseglen, fd) == MAP_FAILED) ++ { ++ errstring = DL_MAP_SEGMENTS_ERROR_MAP_HOLE_FILL; ++ goto unmap_reserved_area; ++ } ++ prev = c; ++ --c; ++ } ++ ++ ++c; ++ l->l_map_start = map_addr; ++ l->l_map_end = l->l_map_start + maplength; ++ l->l_addr = l->l_map_start - c->mapstart; ++ l->l_contiguous = 1; ++ ++ c = loadcmds; ++ while (c < &loadcmds[nloadcmds]) ++ { ++ _dl_postprocess_loadcmd (l, header, c); ++ ++c; ++ } ++ ++ if (l->l_map_start > (ElfW(Addr))map_area_start) ++ { ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("__munmap [%lx-%lx)\n", (ElfW(Addr))map_area_start, l->l_map_start); ++ __munmap(map_area_start, l->l_map_start - (ElfW(Addr))map_area_start); ++ } ++ ++ /* ++ * l->l_map_end is caculated by maplength, l_map_end may end with extra space ++ * use l->l_map_end may munmap extra space part ++ */ ++ if ((ElfW(Addr))map_area_start + maparealen > l_map_end) ++ { ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) ++ _dl_debug_printf("__munmap [%lx-%lx)\n", l_map_end, (ElfW(Addr))map_area_start + maparealen); ++ __munmap((void *)l_map_end, (ElfW(Addr))map_area_start + maparealen - l_map_end); ++ } ++ ++ return NULL; ++ ++unmap_reserved_area: ++ __munmap(map_area_start, maparealen); ++ ++ return errstring; ++} +diff --git a/elf/elf.h b/elf/elf.h +index 4738dfa2..c5315d1b 100644 +--- a/elf/elf.h ++++ b/elf/elf.h +@@ -730,6 +730,8 @@ typedef struct + + /* Legal values for p_flags (segment flags). */ + ++/* libhugetlbfs's hugeedit use 0x00100000, here use another */ ++#define PF_HUGEPAGE (0x01000000) + #define PF_X (1 << 0) /* Segment is executable */ + #define PF_W (1 << 1) /* Segment is writable */ + #define PF_R (1 << 2) /* Segment is readable */ +diff --git a/elf/hugepageedit.c b/elf/hugepageedit.c +new file mode 100644 +index 00000000..14a91a4b +--- /dev/null ++++ b/elf/hugepageedit.c +@@ -0,0 +1,169 @@ ++/* Mark ELF object ELF header hugepage flag Generic version. ++ Copyright (C) 2021-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 ++ . */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* reference kernel load_elf_phdrs program header table size constraint */ ++#define ELF_MIN_ALIGN 4096 ++#define TOOL_NAME "hugepageedit" ++ ++int check_ptr(void *ptr, void *start, size_t len) ++{ ++ if (ptr < start || ptr > start + len) ++ return -1; ++ return 0; ++} ++ ++void print_usage(void) ++{ ++ fprintf(stderr, "%s [-x] [-d] \n" \ ++ "\tdefault mark all PT_LOAD segment PF_HUGEPAGE flag\n" \ ++ "\t-x option only mark executable PT_LOAD segment PF_HUGEPAGE flag\n" \ ++ "\t-d option delete all the PT_LOAD segment PF_HUGEPAGE flag\n", TOOL_NAME); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ int exit_status = -1; ++ int i, opt, delete = 0, exec_only = 0; ++ while ((opt = getopt(argc, argv, "dx")) != -1) ++ { ++ switch (opt) ++ { ++ case 'd': ++ delete = 1; ++ break; ++ case 'x': ++ exec_only = 1; ++ break; ++ default: ++ print_usage(); ++ return 0; ++ } ++ } ++ ++ if (delete && exec_only) ++ { ++ fprintf(stderr, "can not specify -x and -d option at the same time\n"); ++ return -1; ++ } ++ ++ if (optind >= argc) ++ { ++ fprintf(stderr, "Expected argument after options\n"); ++ return -1; ++ } ++ ++ int fd = open(argv[optind], O_RDWR); ++ if (fd < 0) ++ { ++ perror("open"); ++ return -1; ++ } ++ ++ struct stat statbuf; ++ if (fstat(fd, &statbuf) != 0) ++ { ++ perror("fstat"); ++ goto close_fd; ++ } ++ ++ /* this ensures file is large enough to hold ELF header */ ++ if (statbuf.st_size < sizeof (ElfW(Ehdr))) ++ { ++ fprintf(stderr, "file is not large enough to hold ELF header\n"); ++ goto close_fd; ++ } ++ ++ void *ehdr = mmap(NULL, statbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); ++ if (ehdr == MAP_FAILED) ++ { ++ perror("mmap"); ++ goto close_fd; ++ } ++ ++ if (memcmp(((ElfW(Ehdr) *) ehdr)->e_ident, ELFMAG, SELFMAG) != 0) ++ { ++ fprintf(stderr, "file is not ELF format\n"); ++ goto unmap; ++ } ++ ++ if (((ElfW(Ehdr) *)ehdr)->e_phentsize != sizeof(ElfW(Phdr))) ++ { ++ fprintf(stderr, "ELF header's e_phentsize mismatch ElfW(Phdr) size\n"); ++ goto unmap; ++ } ++ ++ unsigned int size = ((ElfW(Ehdr) *)ehdr)->e_phnum * sizeof(ElfW(Phdr)); ++ if (size == 0 || size > ELF_MIN_ALIGN) ++ { ++ fprintf(stderr, "The program header table size specified by ELF header is abnormal: %u\n", size); ++ goto unmap; ++ } ++ ++ void *ephdr_s = ehdr + ((ElfW(Ehdr) *)ehdr)->e_phoff; ++ void *ephdr_e = ehdr + ((ElfW(Ehdr) *)ehdr)->e_phoff + size; ++ ++ if (check_ptr(ephdr_s, ehdr, statbuf.st_size) || ++ check_ptr(ephdr_e, ehdr, statbuf.st_size)) ++ { ++ fprintf(stderr, "ELF porgram header table is not fully mmaped\n"); ++ goto unmap; ++ } ++ ++ ElfW(Phdr) *phdr = (ElfW(Phdr) *)ephdr_s; ++ /* ++ * Here, mark hugepage flag in ELF header e_ident padding bytes won't work. ++ * elf/dl-load.c open_verify will check if shared object ELF header e_ident ++ * padding bytes match expected[EI_NIDENT] byte array which padding bytes ++ * should be zero. If it mismatches, ld.so will exit abnormally ++ */ ++ for (i = 0; i < ((ElfW(Ehdr) *)ehdr)->e_phnum; i++) ++ { ++ if (phdr[i].p_type == PT_LOAD) ++ { ++ if (delete) ++ { ++ phdr[i].p_flags &= ~PF_HUGEPAGE; ++ } ++ else ++ { ++ if (exec_only && !(phdr[i].p_flags & PF_X)) ++ continue; ++ phdr[i].p_flags |= PF_HUGEPAGE; ++ } ++ } ++ } ++ exit_status = 0; ++ ++unmap: ++ munmap(ehdr, statbuf.st_size); ++ ++close_fd: ++ close(fd); ++ ++ return exit_status; ++} +diff --git a/elf/rtld.c b/elf/rtld.c +index 8268849a..491ef6b1 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -2502,6 +2502,40 @@ dl_main (const ElfW(Phdr) *phdr, + /* Once we return, _dl_sysdep_start will invoke + the DT_INIT functions and then *USER_ENTRY. */ + } ++ ++#ifdef HUGEPAGE_SHARED_LIB ++/* prase the hugepage use strategy of loading shared object */ ++static void ++process_dl_hugepage (const char *dl_hugepage) ++{ ++ static const struct ++ { ++ uint64_t option; ++ int flag; ++ } hpopts[] = ++ { ++ {DL_HUGEPAGE_LARGE_IN, DL_HUGEPAGE_LIB_LARGE_IN_FLAG}, ++ }; ++#define nhpopts (sizeof (hpopts) / sizeof (hpopts[0])) ++ ++ if (dl_hugepage == NULL) ++ return; ++ ++ char *endptr; ++ uint64_t val = _dl_strtoul (dl_hugepage, &endptr); ++ /* Invalid digit in input string */ ++ if (*endptr != '\0') ++ return; ++ ++ for (size_t cnt = 0; cnt < nhpopts; ++cnt) ++ if (val == hpopts[cnt].option) ++ { ++ GLRO(dl_debug_mask) |= hpopts[cnt].flag; ++ break; ++ } ++} ++#endif ++ + + /* This is a little helper function for resolving symbols while + tracing the binary. */ +@@ -2637,6 +2671,9 @@ process_envvars (struct dl_main_state *state) + char **runp = _environ; + char *envline; + char *debug_output = NULL; ++#ifdef HUGEPAGE_SHARED_LIB ++ bool hugepage_lib_env = false; ++#endif + + /* This is the default place for profiling data file. */ + GLRO(dl_profile_output) +@@ -2751,6 +2788,16 @@ process_envvars (struct dl_main_state *state) + GLRO(dl_dynamic_weak) = 1; + break; + ++#ifdef HUGEPAGE_SHARED_LIB ++ if (memcmp (envline, "HUGEPAGE_LIB", 12) == 0 && envline[13] != '\0') ++ { ++ hugepage_lib_env = true; ++ process_dl_hugepage(&envline[13]); ++ } ++#endif ++ ++ break; ++ + case 13: + /* We might have some extra environment variable with length 13 + to handle. */ +@@ -2771,6 +2818,13 @@ process_envvars (struct dl_main_state *state) + && memcmp (envline, "PROFILE_OUTPUT", 14) == 0 + && envline[15] != '\0') + GLRO(dl_profile_output) = &envline[15]; ++ ++#ifdef HUGEPAGE_SHARED_LIB ++ if (memcmp (envline, "HUGEPAGE_PROBE", 14) == 0 && ++ envline[15] != '\0') ++ GLRO(dl_debug_mask) |= DL_HUGEPAGE_PROBE_FLAG; ++#endif ++ + break; + + case 16: +@@ -2800,6 +2854,16 @@ process_envvars (struct dl_main_state *state) + } + } + ++#ifdef HUGEPAGE_SHARED_LIB ++ /* LIB_HUGEPAGE_LIB and HUGEPAGE_PROBE are both set. use LIB_HUGEPAGE_LIB */ ++ if ((GLRO(dl_debug_mask) & DL_HUGEPAGE_PROBE_FLAG) && hugepage_lib_env) ++ { ++ GLRO(dl_debug_mask) &= ~DL_HUGEPAGE_PROBE_FLAG; ++ } ++ /* unsetenv LD_HUGEPAGE_LIB, child process should not get this env */ ++ unsetenv("LD_HUGEPAGE_LIB"); ++#endif ++ + /* Extra security for SUID binaries. Remove all dangerous environment + variables. */ + if (__builtin_expect (__libc_enable_secure, 0)) +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index fcbbf697..03cab4c4 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -549,7 +549,11 @@ struct rtld_global_ro + /* These two are used only internally. */ + #define DL_DEBUG_HELP (1 << 10) + #define DL_DEBUG_PRELINK (1 << 11) +- ++#ifdef HUGEPAGE_SHARED_LIB ++#define DL_HUGEPAGE_PROBE_FLAG (1 << 31) ++#define DL_HUGEPAGE_LIB_LARGE_IN_FLAG (1 << 30) ++#define DL_HUGEPAGE_LARGE_IN 1 ++#endif + /* OS version. */ + EXTERN unsigned int _dl_osversion; + /* Platform name. */ +-- +2.31.1 + diff --git a/build-extra-libpthreadcond-so.patch b/0002-add-header-files-for-libphtread_2_17_so.patch similarity index 42% rename from build-extra-libpthreadcond-so.patch rename to 0002-add-header-files-for-libphtread_2_17_so.patch index f3c8e7d6b39e5621c3f6de09613f4e28859eb6fc..98db0ff1833238118aa5f42e6f708ba28a4776a2 100644 --- a/build-extra-libpthreadcond-so.patch +++ b/0002-add-header-files-for-libphtread_2_17_so.patch @@ -1,4993 +1,2609 @@ -From 808cf7c45e187c1889867ac83d047abfdf81c7a3 Mon Sep 17 00:00:00 2001 -From: xuhuijie -Date: Fri, 14 Aug 2020 17:41:59 +0800 -Subject: [PATCH] build extra lipthreadcond so -performance degradation in multi-core scenarios, here is an -extra libpthreadcond.so using old version of the function. you can use it by -adding LD_PRELOAD=./libpthreadcond.so in front of your program (eg: -LD_PRELOAD=./libpthreadcond.so ./test). use with-libpthreadcond to compile -it. warning:2.17 version does not meet the posix standard, you should pay -attention when using it. -https://sourceware.org/git/?p=glibc.git;a=commit;h=ed19993b5b0d05d62cc883571519a67dae481a14 +From 76a50749f7af5935ba3739e815aa6a16ae4440d1 Mon Sep 17 00:00:00 2001 +From: Ulrich Drepper +Date: Tue Nov 26 22:50:54 2002 +0000 +Subject: [PATCH 2/9] build extra lipthreadcond so + +To successfully build some header files that reference glibc-2.17 + +Including but not limited to the following submission: +76a50749f7a +d5efd131d4e +eab380d8ec9 --- - nptl_2_17/Makefile | 52 + - nptl_2_17/bits/pthreadtypes_2_17.h | 121 ++ - nptl_2_17/bits/thread-shared-types_2_17.h | 104 ++ - nptl_2_17/build_libpthreadcondso.sh | 9 + - nptl_2_17/cancellation_2_17.c | 104 ++ - nptl_2_17/cleanup_compat_2_17.c | 50 + - nptl_2_17/libpthreadcond-aarch64.map | 8 + - nptl_2_17/libpthreadcond-x86_64.map | 8 + - nptl_2_17/pthreadP_2_17.h | 620 +++++++++ - nptl_2_17/pthread_2_17.h | 1173 ++++++++++++++++++ - nptl_2_17/pthread_cond_broadcast_2_17.c | 94 ++ - nptl_2_17/pthread_cond_destroy_2_17.c | 85 ++ - nptl_2_17/pthread_cond_init_2_17.c | 50 + - nptl_2_17/pthread_cond_signal_2_17.c | 82 ++ - nptl_2_17/pthread_cond_timedwait_2_17.c | 268 ++++ - nptl_2_17/pthread_cond_wait_2_17.c | 231 ++++ - nptl_2_17/pthread_condattr_getclock_2_17.c | 28 + - nptl_2_17/pthread_condattr_getpshared_2_17.c | 28 + - nptl_2_17/pthread_condattr_init_2_17.c | 34 + - nptl_2_17/pthread_condattr_setclock_2_17.c | 45 + - nptl_2_17/pthread_mutex_cond_lock_2_17.c | 21 + - nptl_2_17/pthread_mutex_lock_2_17.c | 628 ++++++++++ - nptl_2_17/pthread_mutex_unlock_2_17.c | 360 ++++++ - nptl_2_17/pthreadtypes_2_17.h | 179 +++ - nptl_2_17/tpp_2_17.c | 195 +++ - nptl_2_17/unwind_2_17.c | 138 +++ - nptl_2_17/vars_2_17.c | 43 + - 27 files changed, 4758 insertions(+) - create mode 100644 nptl_2_17/Makefile + nptl_2_17/bits/pthreadtypes_2_17.h | 127 +++ + nptl_2_17/bits/thread-shared-types_2_17.h | 186 ++++ + nptl_2_17/internaltypes_2_17.h | 179 ++++ + nptl_2_17/kernel-features_2_17.h | 162 +++ + nptl_2_17/pthreadP_2_17.h | 714 +++++++++++++ + nptl_2_17/pthread_2_17.h | 1175 +++++++++++++++++++++ + 6 files changed, 2543 insertions(+) create mode 100644 nptl_2_17/bits/pthreadtypes_2_17.h create mode 100644 nptl_2_17/bits/thread-shared-types_2_17.h - create mode 100644 nptl_2_17/build_libpthreadcondso.sh - create mode 100644 nptl_2_17/cancellation_2_17.c - create mode 100644 nptl_2_17/cleanup_compat_2_17.c - create mode 100644 nptl_2_17/libpthreadcond-aarch64.map - create mode 100644 nptl_2_17/libpthreadcond-x86_64.map + create mode 100644 nptl_2_17/internaltypes_2_17.h + create mode 100644 nptl_2_17/kernel-features_2_17.h create mode 100644 nptl_2_17/pthreadP_2_17.h create mode 100644 nptl_2_17/pthread_2_17.h - create mode 100644 nptl_2_17/pthread_cond_broadcast_2_17.c - create mode 100644 nptl_2_17/pthread_cond_destroy_2_17.c - create mode 100644 nptl_2_17/pthread_cond_init_2_17.c - create mode 100644 nptl_2_17/pthread_cond_signal_2_17.c - create mode 100644 nptl_2_17/pthread_cond_timedwait_2_17.c - create mode 100644 nptl_2_17/pthread_cond_wait_2_17.c - create mode 100644 nptl_2_17/pthread_condattr_getclock_2_17.c - create mode 100644 nptl_2_17/pthread_condattr_getpshared_2_17.c - create mode 100644 nptl_2_17/pthread_condattr_init_2_17.c - create mode 100644 nptl_2_17/pthread_condattr_setclock_2_17.c - create mode 100644 nptl_2_17/pthread_mutex_cond_lock_2_17.c - create mode 100644 nptl_2_17/pthread_mutex_lock_2_17.c - create mode 100644 nptl_2_17/pthread_mutex_unlock_2_17.c - create mode 100644 nptl_2_17/pthreadtypes_2_17.h - create mode 100644 nptl_2_17/tpp_2_17.c - create mode 100644 nptl_2_17/unwind_2_17.c - create mode 100644 nptl_2_17/vars_2_17.c - - -diff --git a/nptl_2_17/Makefile b/nptl_2_17/Makefile -new file mode 100644 -index 00000000..4c30c5f1 ---- /dev/null -+++ b/nptl_2_17/Makefile -@@ -0,0 +1,52 @@ -+include libpthreadcond_config -+subdir=libpthreadcond -+objdir=../$(build_dir)/ -+ -+ -+ifdef subdir -+.. := ../ -+endif -+ -+objpfx := $(patsubst %//,%/,$(objdir)/$(subdir)/) -+common-objpfx = $(objdir)/ -+common-objdir = $(objdir) -+ -+sysdep_dir := $(..)sysdeps -+export sysdep_dir := $(sysdep_dir) -+ -+include $(common-objpfx)soversions.mk -+include $(common-objpfx)config.make -+ -+uses-callbacks = -fexceptions -+ -+sysdirs := $(foreach D,$(config-sysdirs),$(firstword $(filter /%,$D) $(..)$D)) -+ -++sysdep_dirs = $(sysdirs) -++sysdep_dirs := $(objdir) $(+sysdep_dirs) -+ -++sysdep-includes := $(foreach dir,$(+sysdep_dirs), $(addprefix -I,$(wildcard $(dir)/include) $(dir))) -+ -+compile_obj = vars_2_17.os pthread_cond_wait_2_17.os pthread_cond_timedwait_2_17.os pthread_cond_signal_2_17.os pthread_cond_broadcast_2_17.os pthread_cond_init_2_17.os pthread_cond_destroy_2_17.os cleanup_compat_2_17.os unwind_2_17.os cancellation_2_17.os pthread_mutex_cond_lock_2_17.os pthread_mutex_lock_2_17.os pthread_mutex_unlock_2_17.os pthread_condattr_getclock_2_17.os pthread_condattr_getpshared_2_17.os pthread_condattr_init_2_17.os pthread_condattr_setclock_2_17.os tpp_2_17.os -+compile_obj_dir = $(foreach n,$(compile_obj),../$(build_dir)/nptl/$(n)) -+ -+exist_obj = lowlevellock.os lll_timedlock_wait.os pthread_mutex_conf.os -+ifeq (x86_64, $(arch)) -+exist_obj += elision-lock.os elision-unlock.os elision-timed.os elision-trylock.os -+endif -+ -+exist_obj_dir = $(foreach n,$(exist_obj),../$(build_dir)/nptl/$(n)) -+ -+CFLAGS = -c -std=gnu11 -fgnu89-inline -g -O2 -Wall -Wwrite-strings -Wundef -Werror -fmerge-all-constants -frounding-math -fno-stack-protector -Wstrict-prototypes -Wold-style-definition -fmath-errno -fPIC -ftls-model=initial-exec -DPIC -DSHARED -DTOP_NAMESPACE=glibc -+ -+Headers = -I../include -I../$(build_dir)/nptl $(+sysdep-includes) -I../nptl_2_17 -I../nptl -I../libio -I../. -D_LIBC_REENTRANT -include ../$(build_dir)/libc-modules.h -include include/libc-symbols.h -+ -+all: libpthreadcond.so -+ -+libpthreadcond.so : $(compile_obj) libpthreadcond_pic.a -+ gcc -shared -static-libgcc -Wl,-O1 -Wl,-z,defs -Wl,-dynamic-linker=/usr/local/lib/$(ld.so-version) -B../$(build_dir)/csu/ -Wl,--version-script=libpthreadcond-$(arch).map -Wl,-soname=libpthreadcond.so.0 -Wl,-z,combreloc -Wl,-z,relro -Wl,--hash-style=both -L../$(build_dir) -L../$(build_dir)/math -L../$(build_dir)/elf -L../$(build_dir)/dlfcn -L../$(build_dir)/nss -L../$(build_dir)/nis -L../$(build_dir)/rt -L../$(build_dir)/resolv -L../$(build_dir)/mathvec -L../$(build_dir)/support -L../$(build_dir)/crypt -L../$(build_dir)/nptl -Wl,-rpath-link=../$(build_dir):../$(build_dir)/math:../$(build_dir)/elf:../$(build_dir)/dlfcn:../$(build_dir)/nss:../$(build_dir)/nis:../$(build_dir)/rt:../$(build_dir)/resolv:../$(build_dir)/mathvec:../$(build_dir)/support:../$(build_dir)/crypt:../$(build_dir)/nptl -o ../$(build_dir)/nptl/libpthreadcond.so ../$(build_dir)/csu/abi-note.o -Wl,--whole-archive ../$(build_dir)/nptl/libpthreadcond_pic.a -Wl,--no-whole-archive -Wl,--start-group ../$(build_dir)/libc.so ../$(build_dir)/libc_nonshared.a -Wl,--as-needed ../$(build_dir)/elf/ld.so -Wl,--no-as-needed -Wl,--end-group -+ -+libpthreadcond_pic.a : $(compile_obj_dir) $(exist_obj_dir) -+ ar cruv ../$(build_dir)/nptl/$@ $^ -+ -+$(compile_obj) : %.os : %.c -+ gcc $< $(CFLAGS) $(Headers) -o ../$(build_dir)/nptl/$@ -MD -MP -MF ../$(build_dir)/nptl/$@.dt -MT ../$(build_dir)/nptl/$@ -diff --git a/nptl_2_17/bits/pthreadtypes_2_17.h b/nptl_2_17/bits/pthreadtypes_2_17.h -new file mode 100644 -index 00000000..f501ea4c ---- /dev/null -+++ b/nptl_2_17/bits/pthreadtypes_2_17.h -@@ -0,0 +1,121 @@ -+/* Declaration of common pthread types for all architectures. -+ Copyright (C) 2017-2020 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 -+ . */ -+ -+#ifndef _BITS_PTHREADTYPES_COMMON_H -+# define _BITS_PTHREADTYPES_COMMON_H 1 -+ -+/* For internal mutex and condition variable definitions. */ -+#include -+ -+/* Thread identifiers. The structure of the attribute type is not -+ exposed on purpose. */ -+typedef unsigned long int pthread_t; -+ -+ -+/* Data structures for mutex handling. The structure of the attribute -+ type is not exposed on purpose. */ -+typedef union -+{ -+ char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; -+ int __align; -+} pthread_mutexattr_t; -+ -+ -+/* Data structure for condition variable handling. The structure of -+ the attribute type is not exposed on purpose. */ -+typedef union -+{ -+ char __size[__SIZEOF_PTHREAD_CONDATTR_T]; -+ int __align; -+} pthread_condattr_t; -+ -+ -+/* Keys for thread-specific data */ -+typedef unsigned int pthread_key_t; -+ -+ -+/* Once-only execution */ -+typedef int __ONCE_ALIGNMENT pthread_once_t; -+ -+ -+union pthread_attr_t -+{ -+ char __size[__SIZEOF_PTHREAD_ATTR_T]; -+ long int __align; -+}; -+#ifndef __have_pthread_attr_t -+typedef union pthread_attr_t pthread_attr_t; -+# define __have_pthread_attr_t 1 -+#endif -+ -+ -+typedef union -+{ -+ struct __pthread_mutex_s __data; -+ char __size[__SIZEOF_PTHREAD_MUTEX_T]; -+ long int __align; -+} pthread_mutex_t; -+ -+ -+typedef union -+{ -+ struct __pthread_cond_s __data; -+ char __size[__SIZEOF_PTHREAD_COND_T]; -+ __extension__ long long int __align; -+} pthread_cond_t; -+ -+ -+#if defined __USE_UNIX98 || defined __USE_XOPEN2K -+/* Data structure for reader-writer lock variable handling. The -+ structure of the attribute type is deliberately not exposed. */ -+typedef union -+{ -+ struct __pthread_rwlock_arch_t __data; -+ char __size[__SIZEOF_PTHREAD_RWLOCK_T]; -+ long int __align; -+} pthread_rwlock_t; -+ -+typedef union -+{ -+ char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; -+ long int __align; -+} pthread_rwlockattr_t; -+#endif -+ -+ -+#ifdef __USE_XOPEN2K -+/* POSIX spinlock data type. */ -+typedef volatile int pthread_spinlock_t; -+ -+ -+/* POSIX barriers data type. The structure of the type is -+ deliberately not exposed. */ -+typedef union -+{ -+ char __size[__SIZEOF_PTHREAD_BARRIER_T]; -+ long int __align; -+} pthread_barrier_t; -+ -+typedef union -+{ -+ char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; -+ int __align; -+} pthread_barrierattr_t; -+#endif -+ -+#endif -diff --git a/nptl_2_17/bits/thread-shared-types_2_17.h b/nptl_2_17/bits/thread-shared-types_2_17.h -new file mode 100644 -index 00000000..50e86261 ---- /dev/null -+++ b/nptl_2_17/bits/thread-shared-types_2_17.h -@@ -0,0 +1,104 @@ -+/* Common threading primitives definitions for both POSIX and C11. -+ Copyright (C) 2017-2020 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 -+ . */ -+ -+#ifndef _THREAD_SHARED_TYPES_H -+#define _THREAD_SHARED_TYPES_H 1 -+ -+/* Arch-specific definitions. Each architecture must define the following -+ macros to define the expected sizes of pthread data types: -+ -+ __SIZEOF_PTHREAD_ATTR_T - size of pthread_attr_t. -+ __SIZEOF_PTHREAD_MUTEX_T - size of pthread_mutex_t. -+ __SIZEOF_PTHREAD_MUTEXATTR_T - size of pthread_mutexattr_t. -+ __SIZEOF_PTHREAD_COND_T - size of pthread_cond_t. -+ __SIZEOF_PTHREAD_CONDATTR_T - size of pthread_condattr_t. -+ __SIZEOF_PTHREAD_RWLOCK_T - size of pthread_rwlock_t. -+ __SIZEOF_PTHREAD_RWLOCKATTR_T - size of pthread_rwlockattr_t. -+ __SIZEOF_PTHREAD_BARRIER_T - size of pthread_barrier_t. -+ __SIZEOF_PTHREAD_BARRIERATTR_T - size of pthread_barrierattr_t. -+ -+ The additional macro defines any constraint for the lock alignment -+ inside the thread structures: -+ -+ __LOCK_ALIGNMENT - for internal lock/futex usage. -+ -+ Same idea but for the once locking primitive: -+ -+ __ONCE_ALIGNMENT - for pthread_once_t/once_flag definition. */ -+ -+#include -+ -+ -+/* Common definition of pthread_mutex_t. */ -+ -+typedef struct __pthread_internal_list -+{ -+ struct __pthread_internal_list *__prev; -+ struct __pthread_internal_list *__next; -+} __pthread_list_t; -+ -+typedef struct __pthread_internal_slist -+{ -+ struct __pthread_internal_slist *__next; -+} __pthread_slist_t; -+ -+/* Arch-specific mutex definitions. A generic implementation is provided -+ by sysdeps/nptl/bits/struct_mutex.h. If required, an architecture -+ can override it by defining: -+ -+ 1. struct __pthread_mutex_s (used on both pthread_mutex_t and mtx_t -+ definition). It should contains at least the internal members -+ defined in the generic version. -+ -+ 2. __LOCK_ALIGNMENT for any extra attribute for internal lock used with -+ atomic operations. -+ -+ 3. The macro __PTHREAD_MUTEX_INITIALIZER used for static initialization. -+ It should initialize the mutex internal flag. */ -+ -+#include -+ -+/* Arch-sepecific read-write lock definitions. A generic implementation is -+ provided by struct_rwlock.h. If required, an architecture can override it -+ by defining: -+ -+ 1. struct __pthread_rwlock_arch_t (used on pthread_rwlock_t definition). -+ It should contain at least the internal members defined in the -+ generic version. -+ -+ 2. The macro __PTHREAD_RWLOCK_INITIALIZER used for static initialization. -+ It should initialize the rwlock internal type. */ -+ -+#include -+ -+ -+/* Common definition of pthread_cond_t. */ -+ -+struct __pthread_cond_s -+{ -+ int __lock; -+ unsigned int __futex; -+ __extension__ unsigned long long int __total_seq; -+ __extension__ unsigned long long int __wakeup_seq; -+ __extension__ unsigned long long int __woken_seq; -+ void *__mutex; -+ unsigned int __nwaiters; -+ unsigned int __broadcast_seq; -+}; -+ -+#endif /* _THREAD_SHARED_TYPES_H */ -diff --git a/nptl_2_17/build_libpthreadcondso.sh b/nptl_2_17/build_libpthreadcondso.sh -new file mode 100644 -index 00000000..6997277b ---- /dev/null -+++ b/nptl_2_17/build_libpthreadcondso.sh -@@ -0,0 +1,9 @@ -+#!/bin/sh -+build_arch=$1 -+build_dir=$2 -+config_dir=libpthreadcond_config -+ -+echo arch=${build_arch} > ${config_dir} -+echo build_dir=${build_dir} >> ${config_dir} -+make -+rm -rf ${config_dir} -diff --git a/nptl_2_17/cancellation_2_17.c b/nptl_2_17/cancellation_2_17.c -new file mode 100644 -index 00000000..644d83bf ---- /dev/null -+++ b/nptl_2_17/cancellation_2_17.c -@@ -0,0 +1,104 @@ -+/* Copyright (C) 2002-2020 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Ulrich Drepper , 2002. -+ -+ 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 -+ . */ -+ -+#include "pthreadP_2_17.h" -+#include -+#include -+#include -+ -+ -+/* The next two functions are similar to pthread_setcanceltype() but -+ more specialized for the use in the cancelable functions like write(). -+ They do not need to check parameters etc. These functions must be -+ AS-safe, with the exception of the actual cancellation, because they -+ are called by wrappers around AS-safe functions like write().*/ -+int -+attribute_hidden -+__pthread_enable_asynccancel (void) -+{ -+ struct pthread *self = THREAD_SELF; -+ int oldval = THREAD_GETMEM (self, cancelhandling); -+ -+ while (1) -+ { -+ int newval = oldval | CANCELTYPE_BITMASK; -+ -+ if (newval == oldval) -+ break; -+ -+ int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, -+ oldval); -+ if (__glibc_likely (curval == oldval)) -+ { -+ if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval)) -+ { -+ THREAD_SETMEM (self, result, PTHREAD_CANCELED); -+ __do_cancel (); -+ } -+ -+ break; -+ } -+ -+ /* Prepare the next round. */ -+ oldval = curval; -+ } -+ -+ return oldval; -+} -+ -+/* See the comment for __pthread_enable_asynccancel regarding -+ the AS-safety of this function. */ -+void -+attribute_hidden -+__pthread_disable_asynccancel (int oldtype) -+{ -+ /* If asynchronous cancellation was enabled before we do not have -+ anything to do. */ -+ if (oldtype & CANCELTYPE_BITMASK) -+ return; -+ -+ struct pthread *self = THREAD_SELF; -+ int newval; -+ -+ int oldval = THREAD_GETMEM (self, cancelhandling); -+ -+ while (1) -+ { -+ newval = oldval & ~CANCELTYPE_BITMASK; -+ -+ int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, -+ oldval); -+ if (__glibc_likely (curval == oldval)) -+ break; -+ -+ /* Prepare the next round. */ -+ oldval = curval; -+ } -+ -+ /* We cannot return when we are being canceled. Upon return the -+ thread might be things which would have to be undone. The -+ following loop should loop until the cancellation signal is -+ delivered. */ -+ while (__builtin_expect ((newval & (CANCELING_BITMASK | CANCELED_BITMASK)) -+ == CANCELING_BITMASK, 0)) -+ { -+ futex_wait_simple ((unsigned int *) &self->cancelhandling, newval, -+ FUTEX_PRIVATE); -+ newval = THREAD_GETMEM (self, cancelhandling); -+ } -+} -diff --git a/nptl_2_17/cleanup_compat_2_17.c b/nptl_2_17/cleanup_compat_2_17.c -new file mode 100644 -index 00000000..ccc55836 ---- /dev/null -+++ b/nptl_2_17/cleanup_compat_2_17.c -@@ -0,0 +1,50 @@ -+/* Copyright (C) 2002-2020 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Ulrich Drepper , 2002. -+ -+ 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 -+ . */ -+ -+#include -+#include "pthreadP_2_17.h" -+ -+ -+void -+_pthread_cleanup_push (struct _pthread_cleanup_buffer *buffer, -+ void (*routine) (void *), void *arg) -+{ -+ struct pthread *self = THREAD_SELF; -+ -+ buffer->__routine = routine; -+ buffer->__arg = arg; -+ buffer->__prev = THREAD_GETMEM (self, cleanup); -+ -+ THREAD_SETMEM (self, cleanup, buffer); -+} -+strong_alias (_pthread_cleanup_push, __pthread_cleanup_push) -+ -+ -+void -+_pthread_cleanup_pop (struct _pthread_cleanup_buffer *buffer, int execute) -+{ -+ struct pthread *self __attribute ((unused)) = THREAD_SELF; -+ -+ THREAD_SETMEM (self, cleanup, buffer->__prev); -+ -+ /* If necessary call the cleanup routine after we removed the -+ current cleanup block from the list. */ -+ if (execute) -+ buffer->__routine (buffer->__arg); -+} -+strong_alias (_pthread_cleanup_pop, __pthread_cleanup_pop) -diff --git a/nptl_2_17/libpthreadcond-aarch64.map b/nptl_2_17/libpthreadcond-aarch64.map -new file mode 100644 -index 00000000..d970af06 ---- /dev/null -+++ b/nptl_2_17/libpthreadcond-aarch64.map -@@ -0,0 +1,8 @@ -+GLIBC_2.17 { -+ global: -+ pthread_cond_init; pthread_cond_destroy; -+ pthread_cond_signal; pthread_cond_broadcast; -+ pthread_cond_wait; pthread_cond_timedwait; -+ local: -+ *; -+}; -diff --git a/nptl_2_17/libpthreadcond-x86_64.map b/nptl_2_17/libpthreadcond-x86_64.map -new file mode 100644 -index 00000000..d7f23322 ---- /dev/null -+++ b/nptl_2_17/libpthreadcond-x86_64.map -@@ -0,0 +1,8 @@ -+GLIBC_2.3.2 { -+ global: -+ pthread_cond_init; pthread_cond_destroy; -+ pthread_cond_signal; pthread_cond_broadcast; -+ pthread_cond_wait; pthread_cond_timedwait; -+ local: -+ *; -+}; -diff --git a/nptl_2_17/pthreadP_2_17.h b/nptl_2_17/pthreadP_2_17.h -new file mode 100644 -index 00000000..e195221a ---- /dev/null -+++ b/nptl_2_17/pthreadP_2_17.h -@@ -0,0 +1,620 @@ -+/* Copyright (C) 2002-2020 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Ulrich Drepper , 2002. -+ -+ 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 -+ . */ -+ -+#ifndef _PTHREADP_H -+#define _PTHREADP_H 1 -+ -+#include -+#include -+#include -+#include -+#include "descr.h" -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "pthread_mutex_conf.h" -+ -+ -+/* Atomic operations on TLS memory. */ -+#ifndef THREAD_ATOMIC_CMPXCHG_VAL -+# define THREAD_ATOMIC_CMPXCHG_VAL(descr, member, new, old) \ -+ atomic_compare_and_exchange_val_acq (&(descr)->member, new, old) -+#endif -+ -+#ifndef THREAD_ATOMIC_BIT_SET -+# define THREAD_ATOMIC_BIT_SET(descr, member, bit) \ -+ atomic_bit_set (&(descr)->member, bit) -+#endif -+ -+ -+static inline short max_adaptive_count (void) -+{ -+#if HAVE_TUNABLES -+ return __mutex_aconf.spin_count; -+#else -+ return DEFAULT_ADAPTIVE_COUNT; -+#endif -+} -+ -+ -+/* Magic cookie representing robust mutex with dead owner. */ -+#define PTHREAD_MUTEX_INCONSISTENT INT_MAX -+/* Magic cookie representing not recoverable robust mutex. */ -+#define PTHREAD_MUTEX_NOTRECOVERABLE (INT_MAX - 1) -+ -+#define COND_NWAITERS_SHIFT 1 -+ -+/* Internal mutex type value. */ -+enum -+{ -+ PTHREAD_MUTEX_KIND_MASK_NP = 3, -+ -+ PTHREAD_MUTEX_ELISION_NP = 256, -+ PTHREAD_MUTEX_NO_ELISION_NP = 512, -+ -+ PTHREAD_MUTEX_ROBUST_NORMAL_NP = 16, -+ PTHREAD_MUTEX_ROBUST_RECURSIVE_NP -+ = PTHREAD_MUTEX_ROBUST_NORMAL_NP | PTHREAD_MUTEX_RECURSIVE_NP, -+ PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP -+ = PTHREAD_MUTEX_ROBUST_NORMAL_NP | PTHREAD_MUTEX_ERRORCHECK_NP, -+ PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP -+ = PTHREAD_MUTEX_ROBUST_NORMAL_NP | PTHREAD_MUTEX_ADAPTIVE_NP, -+ PTHREAD_MUTEX_PRIO_INHERIT_NP = 32, -+ PTHREAD_MUTEX_PI_NORMAL_NP -+ = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_NORMAL, -+ PTHREAD_MUTEX_PI_RECURSIVE_NP -+ = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_RECURSIVE_NP, -+ PTHREAD_MUTEX_PI_ERRORCHECK_NP -+ = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ERRORCHECK_NP, -+ PTHREAD_MUTEX_PI_ADAPTIVE_NP -+ = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ADAPTIVE_NP, -+ PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP -+ = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_NORMAL_NP, -+ PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP -+ = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_RECURSIVE_NP, -+ PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP -+ = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP, -+ PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP -+ = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP, -+ PTHREAD_MUTEX_PRIO_PROTECT_NP = 64, -+ PTHREAD_MUTEX_PP_NORMAL_NP -+ = PTHREAD_MUTEX_PRIO_PROTECT_NP | PTHREAD_MUTEX_NORMAL, -+ PTHREAD_MUTEX_PP_RECURSIVE_NP -+ = PTHREAD_MUTEX_PRIO_PROTECT_NP | PTHREAD_MUTEX_RECURSIVE_NP, -+ PTHREAD_MUTEX_PP_ERRORCHECK_NP -+ = PTHREAD_MUTEX_PRIO_PROTECT_NP | PTHREAD_MUTEX_ERRORCHECK_NP, -+ PTHREAD_MUTEX_PP_ADAPTIVE_NP -+ = PTHREAD_MUTEX_PRIO_PROTECT_NP | PTHREAD_MUTEX_ADAPTIVE_NP, -+ PTHREAD_MUTEX_ELISION_FLAGS_NP -+ = PTHREAD_MUTEX_ELISION_NP | PTHREAD_MUTEX_NO_ELISION_NP, -+ -+ PTHREAD_MUTEX_TIMED_ELISION_NP = -+ PTHREAD_MUTEX_TIMED_NP | PTHREAD_MUTEX_ELISION_NP, -+ PTHREAD_MUTEX_TIMED_NO_ELISION_NP = -+ PTHREAD_MUTEX_TIMED_NP | PTHREAD_MUTEX_NO_ELISION_NP, -+}; -+#define PTHREAD_MUTEX_PSHARED_BIT 128 -+ -+/* See concurrency notes regarding __kind in struct __pthread_mutex_s -+ in sysdeps/nptl/bits/thread-shared-types.h. */ -+#define PTHREAD_MUTEX_TYPE(m) \ -+ (atomic_load_relaxed (&((m)->__data.__kind)) & 127) -+/* Don't include NO_ELISION, as that type is always the same -+ as the underlying lock type. */ -+#define PTHREAD_MUTEX_TYPE_ELISION(m) \ -+ (atomic_load_relaxed (&((m)->__data.__kind)) \ -+ & (127 | PTHREAD_MUTEX_ELISION_NP)) -+ -+#if LLL_PRIVATE == 0 && LLL_SHARED == 128 -+# define PTHREAD_MUTEX_PSHARED(m) \ -+ (atomic_load_relaxed (&((m)->__data.__kind)) & 128) -+#else -+# define PTHREAD_MUTEX_PSHARED(m) \ -+ ((atomic_load_relaxed (&((m)->__data.__kind)) & 128) \ -+ ? LLL_SHARED : LLL_PRIVATE) -+#endif -+ -+/* The kernel when waking robust mutexes on exit never uses -+ FUTEX_PRIVATE_FLAG FUTEX_WAKE. */ -+#define PTHREAD_ROBUST_MUTEX_PSHARED(m) LLL_SHARED -+ -+/* Ceiling in __data.__lock. __data.__lock is signed, so don't -+ use the MSB bit in there, but in the mask also include that bit, -+ so that the compiler can optimize & PTHREAD_MUTEX_PRIO_CEILING_MASK -+ masking if the value is then shifted down by -+ PTHREAD_MUTEX_PRIO_CEILING_SHIFT. */ -+#define PTHREAD_MUTEX_PRIO_CEILING_SHIFT 19 -+#define PTHREAD_MUTEX_PRIO_CEILING_MASK 0xfff80000 -+ -+ -+/* Flags in mutex attr. */ -+#define PTHREAD_MUTEXATTR_PROTOCOL_SHIFT 28 -+#define PTHREAD_MUTEXATTR_PROTOCOL_MASK 0x30000000 -+#define PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT 12 -+#define PTHREAD_MUTEXATTR_PRIO_CEILING_MASK 0x00fff000 -+#define PTHREAD_MUTEXATTR_FLAG_ROBUST 0x40000000 -+#define PTHREAD_MUTEXATTR_FLAG_PSHARED 0x80000000 -+#define PTHREAD_MUTEXATTR_FLAG_BITS \ -+ (PTHREAD_MUTEXATTR_FLAG_ROBUST | PTHREAD_MUTEXATTR_FLAG_PSHARED \ -+ | PTHREAD_MUTEXATTR_PROTOCOL_MASK | PTHREAD_MUTEXATTR_PRIO_CEILING_MASK) -+ -+ -+/* For the following, see pthread_rwlock_common.c. */ -+#define PTHREAD_RWLOCK_WRPHASE 1 -+#define PTHREAD_RWLOCK_WRLOCKED 2 -+#define PTHREAD_RWLOCK_RWAITING 4 -+#define PTHREAD_RWLOCK_READER_SHIFT 3 -+#define PTHREAD_RWLOCK_READER_OVERFLOW ((unsigned int) 1 \ -+ << (sizeof (unsigned int) * 8 - 1)) -+#define PTHREAD_RWLOCK_WRHANDOVER ((unsigned int) 1 \ -+ << (sizeof (unsigned int) * 8 - 1)) -+#define PTHREAD_RWLOCK_FUTEX_USED 2 -+ -+ -+/* Bits used in robust mutex implementation. */ -+#define FUTEX_WAITERS 0x80000000 -+#define FUTEX_OWNER_DIED 0x40000000 -+#define FUTEX_TID_MASK 0x3fffffff -+ -+ -+/* pthread_once definitions. See __pthread_once for how these are used. */ -+#define __PTHREAD_ONCE_INPROGRESS 1 -+#define __PTHREAD_ONCE_DONE 2 -+#define __PTHREAD_ONCE_FORK_GEN_INCR 4 -+ -+/* Attribute to indicate thread creation was issued from C11 thrd_create. */ -+#define ATTR_C11_THREAD ((void*)(uintptr_t)-1) -+ -+#if 0 -+/* Condition variable definitions. See __pthread_cond_wait_common. -+ Need to be defined here so there is one place from which -+ nptl_lock_constants can grab them. */ -+#define __PTHREAD_COND_CLOCK_MONOTONIC_MASK 2 -+#define __PTHREAD_COND_SHARED_MASK 1 -+#endif -+ -+/* Internal variables. */ -+ -+ -+/* Default pthread attributes. */ -+extern struct pthread_attr __default_pthread_attr attribute_hidden; -+extern int __default_pthread_attr_lock attribute_hidden; -+ -+/* Size and alignment of static TLS block. */ -+extern size_t __static_tls_size attribute_hidden; -+extern size_t __static_tls_align_m1 attribute_hidden; -+ -+/* Flag whether the machine is SMP or not. */ -+extern int __is_smp attribute_hidden; -+ -+/* Thread descriptor handling. */ -+extern list_t __stack_user; -+hidden_proto (__stack_user) -+ -+/* Attribute handling. */ -+extern struct pthread_attr *__attr_list attribute_hidden; -+extern int __attr_list_lock attribute_hidden; -+ -+/* Concurrency handling. */ -+extern int __concurrency_level attribute_hidden; -+ -+/* Thread-local data key handling. */ -+extern struct pthread_key_struct __pthread_keys[PTHREAD_KEYS_MAX]; -+hidden_proto (__pthread_keys) -+ -+/* Number of threads running. */ -+extern unsigned int __nptl_nthreads attribute_hidden; -+ -+#ifndef __ASSUME_SET_ROBUST_LIST -+/* Negative if we do not have the system call and we can use it. */ -+extern int __set_robust_list_avail attribute_hidden; -+#endif -+ -+/* Thread Priority Protection. */ -+extern int __sched_fifo_min_prio attribute_hidden; -+extern int __sched_fifo_max_prio attribute_hidden; -+extern void __init_sched_fifo_prio (void) attribute_hidden; -+extern int __pthread_tpp_change_priority (int prev_prio, int new_prio) -+ attribute_hidden; -+extern int __pthread_current_priority (void) attribute_hidden; -+ -+/* The library can run in debugging mode where it performs a lot more -+ tests. */ -+extern int __pthread_debug attribute_hidden; -+/** For now disable debugging support. */ -+#if 0 -+# define DEBUGGING_P __builtin_expect (__pthread_debug, 0) -+# define INVALID_TD_P(pd) (DEBUGGING_P && __find_in_stack_list (pd) == NULL) -+# define INVALID_NOT_TERMINATED_TD_P(pd) INVALID_TD_P (pd) -+#else -+# define DEBUGGING_P 0 -+/* Simplified test. This will not catch all invalid descriptors but -+ is better than nothing. And if the test triggers the thread -+ descriptor is guaranteed to be invalid. */ -+# define INVALID_TD_P(pd) __builtin_expect ((pd)->tid <= 0, 0) -+# define INVALID_NOT_TERMINATED_TD_P(pd) __builtin_expect ((pd)->tid < 0, 0) -+#endif -+ -+ -+/* Cancellation test. */ -+#define CANCELLATION_P(self) \ -+ do { \ -+ int cancelhandling = THREAD_GETMEM (self, cancelhandling); \ -+ if (CANCEL_ENABLED_AND_CANCELED (cancelhandling)) \ -+ { \ -+ THREAD_SETMEM (self, result, PTHREAD_CANCELED); \ -+ __do_cancel (); \ -+ } \ -+ } while (0) -+ -+ -+extern void __pthread_unwind (__pthread_unwind_buf_t *__buf) -+ __cleanup_fct_attribute __attribute ((__noreturn__)) -+ ; -+extern void __pthread_unwind_next (__pthread_unwind_buf_t *__buf) -+ __cleanup_fct_attribute __attribute ((__noreturn__)) -+#ifndef SHARED -+ weak_function -+#endif -+ ; -+extern void __pthread_register_cancel (__pthread_unwind_buf_t *__buf) -+ __cleanup_fct_attribute; -+extern void __pthread_unregister_cancel (__pthread_unwind_buf_t *__buf) -+ __cleanup_fct_attribute; -+hidden_proto (__pthread_unwind) -+hidden_proto (__pthread_unwind_next) -+hidden_proto (__pthread_register_cancel) -+hidden_proto (__pthread_unregister_cancel) -+# ifdef SHARED -+extern void attribute_hidden pthread_cancel_init (void); -+# endif -+extern void __nptl_unwind_freeres (void) attribute_hidden; -+ -+/* Called when a thread reacts on a cancellation request. */ -+static inline void -+__attribute ((noreturn, always_inline)) -+__do_cancel (void) -+{ -+ struct pthread *self = THREAD_SELF; -+ -+ /* Make sure we get no more cancellations. */ -+ THREAD_ATOMIC_BIT_SET (self, cancelhandling, EXITING_BIT); -+ -+ __pthread_unwind ((__pthread_unwind_buf_t *) -+ THREAD_GETMEM (self, cleanup_jmp_buf)); -+} -+ -+ -+/* Internal prototypes. */ -+ -+/* Thread list handling. */ -+extern struct pthread *__find_in_stack_list (struct pthread *pd) -+ attribute_hidden; -+ -+/* Deallocate a thread's stack after optionally making sure the thread -+ descriptor is still valid. */ -+extern void __free_tcb (struct pthread *pd) attribute_hidden; -+ -+/* Free allocated stack. */ -+extern void __deallocate_stack (struct pthread *pd) attribute_hidden; -+ -+/* Mark all the stacks except for the current one as available. This -+ function also re-initializes the lock for the stack cache. */ -+extern void __reclaim_stacks (void) attribute_hidden; -+ -+/* Make all threads's stacks executable. */ -+extern int __make_stacks_executable (void **stack_endp) attribute_hidden; -+ -+/* longjmp handling. */ -+extern void __pthread_cleanup_upto (__jmp_buf target, char *targetframe); -+hidden_proto (__pthread_cleanup_upto) -+ -+ -+/* Functions with versioned interfaces. */ -+extern int __pthread_create_2_1 (pthread_t *newthread, -+ const pthread_attr_t *attr, -+ void *(*start_routine) (void *), void *arg); -+extern int __pthread_create_2_0 (pthread_t *newthread, -+ const pthread_attr_t *attr, -+ void *(*start_routine) (void *), void *arg); -+extern int __pthread_attr_init_2_1 (pthread_attr_t *attr); -+extern int __pthread_attr_init_2_0 (pthread_attr_t *attr); -+ -+ -+/* Event handlers for libthread_db interface. */ -+extern void __nptl_create_event (void); -+extern void __nptl_death_event (void); -+hidden_proto (__nptl_create_event) -+hidden_proto (__nptl_death_event) -+ -+/* Register the generation counter in the libpthread with the libc. */ -+#ifdef TLS_MULTIPLE_THREADS_IN_TCB -+extern void __libc_pthread_init (unsigned long int *ptr, -+ void (*reclaim) (void), -+ const struct pthread_functions *functions); -+#else -+extern int *__libc_pthread_init (unsigned long int *ptr, -+ void (*reclaim) (void), -+ const struct pthread_functions *functions); -+ -+/* Variable set to a nonzero value either if more than one thread runs or ran, -+ or if a single-threaded process is trying to cancel itself. See -+ nptl/descr.h for more context on the single-threaded process case. */ -+extern int __pthread_multiple_threads attribute_hidden; -+/* Pointer to the corresponding variable in libc. */ -+extern int *__libc_multiple_threads_ptr attribute_hidden; -+#endif -+ -+extern void __pthread_init_static_tls (struct link_map *) attribute_hidden; -+ -+extern size_t __pthread_get_minstack (const pthread_attr_t *attr); -+ -+/* Namespace save aliases. */ -+extern int __pthread_getschedparam (pthread_t thread_id, int *policy, -+ struct sched_param *param); -+extern int __pthread_setschedparam (pthread_t thread_id, int policy, -+ const struct sched_param *param); -+extern int __pthread_setcancelstate (int state, int *oldstate); -+extern int __pthread_mutex_init (pthread_mutex_t *__mutex, -+ const pthread_mutexattr_t *__mutexattr); -+extern int __pthread_mutex_destroy (pthread_mutex_t *__mutex); -+extern int __pthread_mutex_trylock (pthread_mutex_t *_mutex); -+extern int __pthread_mutex_lock (pthread_mutex_t *__mutex); -+extern int __pthread_mutex_timedlock (pthread_mutex_t *__mutex, -+ const struct timespec *__abstime); -+extern int __pthread_mutex_cond_lock (pthread_mutex_t *__mutex) -+ attribute_hidden; -+extern void __pthread_mutex_cond_lock_adjust (pthread_mutex_t *__mutex) -+ attribute_hidden; -+extern int __pthread_mutex_unlock (pthread_mutex_t *__mutex); -+extern int __pthread_mutex_unlock_usercnt (pthread_mutex_t *__mutex, -+ int __decr) attribute_hidden; -+extern int __pthread_mutexattr_init (pthread_mutexattr_t *attr); -+extern int __pthread_mutexattr_destroy (pthread_mutexattr_t *attr); -+extern int __pthread_mutexattr_settype (pthread_mutexattr_t *attr, int kind); -+extern int __pthread_attr_destroy (pthread_attr_t *attr); -+extern int __pthread_attr_getdetachstate (const pthread_attr_t *attr, -+ int *detachstate); -+extern int __pthread_attr_setdetachstate (pthread_attr_t *attr, -+ int detachstate); -+extern int __pthread_attr_getinheritsched (const pthread_attr_t *attr, -+ int *inherit); -+extern int __pthread_attr_setinheritsched (pthread_attr_t *attr, int inherit); -+extern int __pthread_attr_getschedparam (const pthread_attr_t *attr, -+ struct sched_param *param); -+extern int __pthread_attr_setschedparam (pthread_attr_t *attr, -+ const struct sched_param *param); -+extern int __pthread_attr_getschedpolicy (const pthread_attr_t *attr, -+ int *policy); -+extern int __pthread_attr_setschedpolicy (pthread_attr_t *attr, int policy); -+extern int __pthread_attr_getscope (const pthread_attr_t *attr, int *scope); -+extern int __pthread_attr_setscope (pthread_attr_t *attr, int scope); -+extern int __pthread_attr_getstackaddr (const pthread_attr_t *__restrict -+ __attr, void **__restrict __stackaddr); -+extern int __pthread_attr_setstackaddr (pthread_attr_t *__attr, -+ void *__stackaddr); -+extern int __pthread_attr_getstacksize (const pthread_attr_t *__restrict -+ __attr, -+ size_t *__restrict __stacksize); -+extern int __pthread_attr_setstacksize (pthread_attr_t *__attr, -+ size_t __stacksize); -+extern int __pthread_attr_getstack (const pthread_attr_t *__restrict __attr, -+ void **__restrict __stackaddr, -+ size_t *__restrict __stacksize); -+extern int __pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr, -+ size_t __stacksize); -+extern int __pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock, -+ const pthread_rwlockattr_t *__restrict -+ __attr); -+extern int __pthread_rwlock_destroy (pthread_rwlock_t *__rwlock); -+extern int __pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock); -+extern int __pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock); -+extern int __pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock); -+extern int __pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock); -+extern int __pthread_rwlock_unlock (pthread_rwlock_t *__rwlock); -+extern int __pthread_cond_broadcast (pthread_cond_t *cond); -+extern int __pthread_cond_destroy (pthread_cond_t *cond); -+extern int __pthread_cond_init (pthread_cond_t *cond, -+ const pthread_condattr_t *cond_attr); -+extern int __pthread_cond_signal (pthread_cond_t *cond); -+extern int __pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex); -+extern int __pthread_cond_timedwait (pthread_cond_t *cond, -+ pthread_mutex_t *mutex, -+ const struct timespec *abstime); -+extern int __pthread_condattr_destroy (pthread_condattr_t *attr); -+extern int __pthread_condattr_init (pthread_condattr_t *attr); -+extern int __pthread_key_create (pthread_key_t *key, void (*destr) (void *)); -+extern int __pthread_key_delete (pthread_key_t key); -+extern void *__pthread_getspecific (pthread_key_t key); -+extern int __pthread_setspecific (pthread_key_t key, const void *value); -+extern int __pthread_once (pthread_once_t *once_control, -+ void (*init_routine) (void)); -+extern int __pthread_atfork (void (*prepare) (void), void (*parent) (void), -+ void (*child) (void)); -+extern pthread_t __pthread_self (void); -+extern int __pthread_equal (pthread_t thread1, pthread_t thread2); -+extern int __pthread_detach (pthread_t th); -+extern int __pthread_cancel (pthread_t th); -+extern int __pthread_kill (pthread_t threadid, int signo); -+extern void __pthread_exit (void *value) __attribute__ ((__noreturn__)); -+extern int __pthread_join (pthread_t threadid, void **thread_return); -+extern int __pthread_setcanceltype (int type, int *oldtype); -+extern int __pthread_enable_asynccancel (void) attribute_hidden; -+extern void __pthread_disable_asynccancel (int oldtype) attribute_hidden; -+extern void __pthread_testcancel (void); -+extern int __pthread_clockjoin_ex (pthread_t, void **, clockid_t, -+ const struct timespec *, bool) -+ attribute_hidden; -+ -+ -+hidden_proto (__pthread_mutex_init) -+hidden_proto (__pthread_mutex_destroy) -+hidden_proto (__pthread_mutex_lock) -+hidden_proto (__pthread_mutex_trylock) -+hidden_proto (__pthread_mutex_unlock) -+hidden_proto (__pthread_rwlock_rdlock) -+hidden_proto (__pthread_rwlock_wrlock) -+hidden_proto (__pthread_rwlock_unlock) -+hidden_proto (__pthread_key_create) -+hidden_proto (__pthread_getspecific) -+hidden_proto (__pthread_setspecific) -+hidden_proto (__pthread_once) -+hidden_proto (__pthread_setcancelstate) -+hidden_proto (__pthread_testcancel) -+hidden_proto (__pthread_mutexattr_init) -+hidden_proto (__pthread_mutexattr_settype) -+ -+extern int __pthread_cond_broadcast_2_0 (pthread_cond_2_0_t *cond); -+extern int __pthread_cond_destroy_2_0 (pthread_cond_2_0_t *cond); -+extern int __pthread_cond_init_2_0 (pthread_cond_2_0_t *cond, -+ const pthread_condattr_t *cond_attr); -+extern int __pthread_cond_signal_2_0 (pthread_cond_2_0_t *cond); -+extern int __pthread_cond_timedwait_2_0 (pthread_cond_2_0_t *cond, -+ pthread_mutex_t *mutex, -+ const struct timespec *abstime); -+extern int __pthread_cond_wait_2_0 (pthread_cond_2_0_t *cond, -+ pthread_mutex_t *mutex); -+ -+extern int __pthread_getaffinity_np (pthread_t th, size_t cpusetsize, -+ cpu_set_t *cpuset); -+ -+/* Special versions which use non-exported functions. */ -+extern void __pthread_cleanup_push (struct _pthread_cleanup_buffer *buffer, -+ void (*routine) (void *), void *arg) -+ attribute_hidden; -+ -+/* Replace cleanup macros defined in with internal -+ versions that don't depend on unwind info and better support -+ cancellation. */ -+# undef pthread_cleanup_push -+# define pthread_cleanup_push(routine,arg) \ -+ { struct _pthread_cleanup_buffer _buffer; \ -+ __pthread_cleanup_push (&_buffer, (routine), (arg)); -+ -+extern void __pthread_cleanup_pop (struct _pthread_cleanup_buffer *buffer, -+ int execute) attribute_hidden; -+# undef pthread_cleanup_pop -+# define pthread_cleanup_pop(execute) \ -+ __pthread_cleanup_pop (&_buffer, (execute)); } -+ -+extern void __pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *buffer, -+ void (*routine) (void *), void *arg); -+extern void __pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *buffer, -+ int execute); -+ -+/* Old cleanup interfaces, still used in libc.so. */ -+extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *buffer, -+ void (*routine) (void *), void *arg); -+extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *buffer, -+ int execute); -+extern void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *buffer, -+ void (*routine) (void *), void *arg); -+extern void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *buffer, -+ int execute); -+ -+extern void __nptl_deallocate_tsd (void) attribute_hidden; -+ -+extern void __nptl_setxid_error (struct xid_command *cmdp, int error) -+ attribute_hidden; -+extern int __nptl_setxid (struct xid_command *cmdp) attribute_hidden; -+#ifndef SHARED -+extern void __nptl_set_robust (struct pthread *self); -+#endif -+ -+extern void __nptl_stacks_freeres (void) attribute_hidden; -+extern void __shm_directory_freeres (void) attribute_hidden; -+ -+extern void __wait_lookup_done (void) attribute_hidden; -+ -+#ifdef SHARED -+# define PTHREAD_STATIC_FN_REQUIRE(name) -+#else -+# define PTHREAD_STATIC_FN_REQUIRE(name) __asm (".globl " #name); -+#endif -+ -+/* Test if the mutex is suitable for the FUTEX_WAIT_REQUEUE_PI operation. */ -+#if (defined lll_futex_wait_requeue_pi \ -+ && defined __ASSUME_REQUEUE_PI) -+# define USE_REQUEUE_PI(mut) \ -+ ((mut) && (mut) != (void *) ~0l \ -+ && (((mut)->__data.__kind \ -+ & (PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_NORMAL_NP)) \ -+ == PTHREAD_MUTEX_PRIO_INHERIT_NP)) -+#else -+# define USE_REQUEUE_PI(mut) 0 -+#endif -+ -+/* Returns 0 if POL is a valid scheduling policy. */ -+static inline int -+check_sched_policy_attr (int pol) -+{ -+ if (pol == SCHED_OTHER || pol == SCHED_FIFO || pol == SCHED_RR) -+ return 0; -+ -+ return EINVAL; -+} -+ -+/* Returns 0 if PR is within the accepted range of priority values for -+ the scheduling policy POL or EINVAL otherwise. */ -+static inline int -+check_sched_priority_attr (int pr, int pol) -+{ -+ int min = __sched_get_priority_min (pol); -+ int max = __sched_get_priority_max (pol); -+ -+ if (min >= 0 && max >= 0 && pr >= min && pr <= max) -+ return 0; -+ -+ return EINVAL; -+} -+ -+/* Returns 0 if ST is a valid stack size for a thread stack and EINVAL -+ otherwise. */ -+static inline int -+check_stacksize_attr (size_t st) -+{ -+ if (st >= PTHREAD_STACK_MIN) -+ return 0; -+ -+ return EINVAL; -+} -+ -+#define ASSERT_TYPE_SIZE(type, size) \ -+ _Static_assert (sizeof (type) == size, \ -+ "sizeof (" #type ") != " #size) -+ -+#define ASSERT_PTHREAD_INTERNAL_SIZE(type, internal) \ -+ _Static_assert (sizeof ((type) { { 0 } }).__size >= sizeof (internal),\ -+ "sizeof (" #type ".__size) < sizeof (" #internal ")") -+ -+#define ASSERT_PTHREAD_STRING(x) __STRING (x) -+#define ASSERT_PTHREAD_INTERNAL_OFFSET(type, member, offset) \ -+ _Static_assert (offsetof (type, member) == offset, \ -+ "offset of " #member " field of " #type " != " \ -+ ASSERT_PTHREAD_STRING (offset)) -+#define ASSERT_PTHREAD_INTERNAL_MEMBER_SIZE(type, member, mtype) \ -+ _Static_assert (sizeof (((type) { 0 }).member) != 8, \ -+ "sizeof (" #type "." #member ") != sizeof (" #mtype "))") -+ -+#endif /* pthreadP.h */ -diff --git a/nptl_2_17/pthread_2_17.h b/nptl_2_17/pthread_2_17.h -new file mode 100644 -index 00000000..3954770a ---- /dev/null -+++ b/nptl_2_17/pthread_2_17.h -@@ -0,0 +1,1173 @@ -+/* Copyright (C) 2002-2020 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 -+ . */ -+ -+#ifndef _PTHREAD_H -+#define _PTHREAD_H 1 -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+ -+/* Detach state. */ -+enum -+{ -+ PTHREAD_CREATE_JOINABLE, -+#define PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_JOINABLE -+ PTHREAD_CREATE_DETACHED -+#define PTHREAD_CREATE_DETACHED PTHREAD_CREATE_DETACHED -+}; -+ -+ -+/* Mutex types. */ -+enum -+{ -+ PTHREAD_MUTEX_TIMED_NP, -+ PTHREAD_MUTEX_RECURSIVE_NP, -+ PTHREAD_MUTEX_ERRORCHECK_NP, -+ PTHREAD_MUTEX_ADAPTIVE_NP -+#if defined __USE_UNIX98 || defined __USE_XOPEN2K8 -+ , -+ PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_TIMED_NP, -+ PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP, -+ PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP, -+ PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL -+#endif -+#ifdef __USE_GNU -+ /* For compatibility. */ -+ , PTHREAD_MUTEX_FAST_NP = PTHREAD_MUTEX_TIMED_NP -+#endif -+}; -+ -+ -+#ifdef __USE_XOPEN2K -+/* Robust mutex or not flags. */ -+enum -+{ -+ PTHREAD_MUTEX_STALLED, -+ PTHREAD_MUTEX_STALLED_NP = PTHREAD_MUTEX_STALLED, -+ PTHREAD_MUTEX_ROBUST, -+ PTHREAD_MUTEX_ROBUST_NP = PTHREAD_MUTEX_ROBUST -+}; -+#endif -+ -+ -+#if defined __USE_POSIX199506 || defined __USE_UNIX98 -+/* Mutex protocols. */ -+enum -+{ -+ PTHREAD_PRIO_NONE, -+ PTHREAD_PRIO_INHERIT, -+ PTHREAD_PRIO_PROTECT -+}; -+#endif -+ -+ -+#define PTHREAD_MUTEX_INITIALIZER \ -+ { { __PTHREAD_MUTEX_INITIALIZER (PTHREAD_MUTEX_TIMED_NP) } } -+#ifdef __USE_GNU -+# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \ -+ { { __PTHREAD_MUTEX_INITIALIZER (PTHREAD_MUTEX_RECURSIVE_NP) } } -+# define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \ -+ { { __PTHREAD_MUTEX_INITIALIZER (PTHREAD_MUTEX_ERRORCHECK_NP) } } -+# define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \ -+ { { __PTHREAD_MUTEX_INITIALIZER (PTHREAD_MUTEX_ADAPTIVE_NP) } } -+#endif -+ -+ -+/* Read-write lock types. */ -+#if defined __USE_UNIX98 || defined __USE_XOPEN2K -+enum -+{ -+ PTHREAD_RWLOCK_PREFER_READER_NP, -+ PTHREAD_RWLOCK_PREFER_WRITER_NP, -+ PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, -+ PTHREAD_RWLOCK_DEFAULT_NP = PTHREAD_RWLOCK_PREFER_READER_NP -+}; -+ -+ -+/* Read-write lock initializers. */ -+# define PTHREAD_RWLOCK_INITIALIZER \ -+ { { __PTHREAD_RWLOCK_INITIALIZER (PTHREAD_RWLOCK_DEFAULT_NP) } } -+# ifdef __USE_GNU -+# define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \ -+ { { __PTHREAD_RWLOCK_INITIALIZER (PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP) } } -+# endif -+#endif /* Unix98 or XOpen2K */ -+ -+ -+/* Scheduler inheritance. */ -+enum -+{ -+ PTHREAD_INHERIT_SCHED, -+#define PTHREAD_INHERIT_SCHED PTHREAD_INHERIT_SCHED -+ PTHREAD_EXPLICIT_SCHED -+#define PTHREAD_EXPLICIT_SCHED PTHREAD_EXPLICIT_SCHED -+}; -+ -+ -+/* Scope handling. */ -+enum -+{ -+ PTHREAD_SCOPE_SYSTEM, -+#define PTHREAD_SCOPE_SYSTEM PTHREAD_SCOPE_SYSTEM -+ PTHREAD_SCOPE_PROCESS -+#define PTHREAD_SCOPE_PROCESS PTHREAD_SCOPE_PROCESS -+}; -+ -+ -+/* Process shared or private flag. */ -+enum -+{ -+ PTHREAD_PROCESS_PRIVATE, -+#define PTHREAD_PROCESS_PRIVATE PTHREAD_PROCESS_PRIVATE -+ PTHREAD_PROCESS_SHARED -+#define PTHREAD_PROCESS_SHARED PTHREAD_PROCESS_SHARED -+}; -+ -+ -+ -+/* Conditional variable handling. */ -+#define PTHREAD_COND_INITIALIZER { { 0, 0, 0, 0, 0, (void *) 0, 0, 0 } } -+ -+ -+/* Cleanup buffers */ -+struct _pthread_cleanup_buffer -+{ -+ void (*__routine) (void *); /* Function to call. */ -+ void *__arg; /* Its argument. */ -+ int __canceltype; /* Saved cancellation type. */ -+ struct _pthread_cleanup_buffer *__prev; /* Chaining of cleanup functions. */ -+}; -+ -+/* Cancellation */ -+enum -+{ -+ PTHREAD_CANCEL_ENABLE, -+#define PTHREAD_CANCEL_ENABLE PTHREAD_CANCEL_ENABLE -+ PTHREAD_CANCEL_DISABLE -+#define PTHREAD_CANCEL_DISABLE PTHREAD_CANCEL_DISABLE -+}; -+enum -+{ -+ PTHREAD_CANCEL_DEFERRED, -+#define PTHREAD_CANCEL_DEFERRED PTHREAD_CANCEL_DEFERRED -+ PTHREAD_CANCEL_ASYNCHRONOUS -+#define PTHREAD_CANCEL_ASYNCHRONOUS PTHREAD_CANCEL_ASYNCHRONOUS -+}; -+#define PTHREAD_CANCELED ((void *) -1) -+ -+ -+/* Single execution handling. */ -+#define PTHREAD_ONCE_INIT 0 -+ -+ -+#ifdef __USE_XOPEN2K -+/* Value returned by 'pthread_barrier_wait' for one of the threads after -+ the required number of threads have called this function. -+ -1 is distinct from 0 and all errno constants */ -+# define PTHREAD_BARRIER_SERIAL_THREAD -1 -+#endif -+ -+ -+__BEGIN_DECLS -+ -+/* Create a new thread, starting with execution of START-ROUTINE -+ getting passed ARG. Creation attributed come from ATTR. The new -+ handle is stored in *NEWTHREAD. */ -+extern int pthread_create (pthread_t *__restrict __newthread, -+ const pthread_attr_t *__restrict __attr, -+ void *(*__start_routine) (void *), -+ void *__restrict __arg) __THROWNL __nonnull ((1, 3)); -+ -+/* Terminate calling thread. -+ -+ The registered cleanup handlers are called via exception handling -+ so we cannot mark this function with __THROW.*/ -+extern void pthread_exit (void *__retval) __attribute__ ((__noreturn__)); -+ -+/* Make calling thread wait for termination of the thread TH. The -+ exit status of the thread is stored in *THREAD_RETURN, if THREAD_RETURN -+ is not NULL. -+ -+ This function is a cancellation point and therefore not marked with -+ __THROW. */ -+extern int pthread_join (pthread_t __th, void **__thread_return); -+ -+#ifdef __USE_GNU -+/* Check whether thread TH has terminated. If yes return the status of -+ the thread in *THREAD_RETURN, if THREAD_RETURN is not NULL. */ -+extern int pthread_tryjoin_np (pthread_t __th, void **__thread_return) __THROW; -+ -+/* Make calling thread wait for termination of the thread TH, but only -+ until TIMEOUT. The exit status of the thread is stored in -+ *THREAD_RETURN, if THREAD_RETURN is not NULL. -+ -+ This function is a cancellation point and therefore not marked with -+ __THROW. */ -+extern int pthread_timedjoin_np (pthread_t __th, void **__thread_return, -+ const struct timespec *__abstime); -+ -+/* Make calling thread wait for termination of the thread TH, but only -+ until TIMEOUT measured against the clock specified by CLOCKID. The -+ exit status of the thread is stored in *THREAD_RETURN, if -+ THREAD_RETURN is not NULL. -+ -+ This function is a cancellation point and therefore not marked with -+ __THROW. */ -+extern int pthread_clockjoin_np (pthread_t __th, void **__thread_return, -+ clockid_t __clockid, -+ const struct timespec *__abstime); -+#endif -+ -+/* Indicate that the thread TH is never to be joined with PTHREAD_JOIN. -+ The resources of TH will therefore be freed immediately when it -+ terminates, instead of waiting for another thread to perform PTHREAD_JOIN -+ on it. */ -+extern int pthread_detach (pthread_t __th) __THROW; -+ -+ -+/* Obtain the identifier of the current thread. */ -+extern pthread_t pthread_self (void) __THROW __attribute__ ((__const__)); -+ -+/* Compare two thread identifiers. */ -+extern int pthread_equal (pthread_t __thread1, pthread_t __thread2) -+ __THROW __attribute__ ((__const__)); -+ -+ -+/* Thread attribute handling. */ -+ -+/* Initialize thread attribute *ATTR with default attributes -+ (detachstate is PTHREAD_JOINABLE, scheduling policy is SCHED_OTHER, -+ no user-provided stack). */ -+extern int pthread_attr_init (pthread_attr_t *__attr) __THROW __nonnull ((1)); -+ -+/* Destroy thread attribute *ATTR. */ -+extern int pthread_attr_destroy (pthread_attr_t *__attr) -+ __THROW __nonnull ((1)); -+ -+/* Get detach state attribute. */ -+extern int pthread_attr_getdetachstate (const pthread_attr_t *__attr, -+ int *__detachstate) -+ __THROW __nonnull ((1, 2)); -+ -+/* Set detach state attribute. */ -+extern int pthread_attr_setdetachstate (pthread_attr_t *__attr, -+ int __detachstate) -+ __THROW __nonnull ((1)); -+ -+ -+/* Get the size of the guard area created for stack overflow protection. */ -+extern int pthread_attr_getguardsize (const pthread_attr_t *__attr, -+ size_t *__guardsize) -+ __THROW __nonnull ((1, 2)); -+ -+/* Set the size of the guard area created for stack overflow protection. */ -+extern int pthread_attr_setguardsize (pthread_attr_t *__attr, -+ size_t __guardsize) -+ __THROW __nonnull ((1)); -+ -+ -+/* Return in *PARAM the scheduling parameters of *ATTR. */ -+extern int pthread_attr_getschedparam (const pthread_attr_t *__restrict __attr, -+ struct sched_param *__restrict __param) -+ __THROW __nonnull ((1, 2)); -+ -+/* Set scheduling parameters (priority, etc) in *ATTR according to PARAM. */ -+extern int pthread_attr_setschedparam (pthread_attr_t *__restrict __attr, -+ const struct sched_param *__restrict -+ __param) __THROW __nonnull ((1, 2)); -+ -+/* Return in *POLICY the scheduling policy of *ATTR. */ -+extern int pthread_attr_getschedpolicy (const pthread_attr_t *__restrict -+ __attr, int *__restrict __policy) -+ __THROW __nonnull ((1, 2)); -+ -+/* Set scheduling policy in *ATTR according to POLICY. */ -+extern int pthread_attr_setschedpolicy (pthread_attr_t *__attr, int __policy) -+ __THROW __nonnull ((1)); -+ -+/* Return in *INHERIT the scheduling inheritance mode of *ATTR. */ -+extern int pthread_attr_getinheritsched (const pthread_attr_t *__restrict -+ __attr, int *__restrict __inherit) -+ __THROW __nonnull ((1, 2)); -+ -+/* Set scheduling inheritance mode in *ATTR according to INHERIT. */ -+extern int pthread_attr_setinheritsched (pthread_attr_t *__attr, -+ int __inherit) -+ __THROW __nonnull ((1)); -+ -+ -+/* Return in *SCOPE the scheduling contention scope of *ATTR. */ -+extern int pthread_attr_getscope (const pthread_attr_t *__restrict __attr, -+ int *__restrict __scope) -+ __THROW __nonnull ((1, 2)); -+ -+/* Set scheduling contention scope in *ATTR according to SCOPE. */ -+extern int pthread_attr_setscope (pthread_attr_t *__attr, int __scope) -+ __THROW __nonnull ((1)); -+ -+/* Return the previously set address for the stack. */ -+extern int pthread_attr_getstackaddr (const pthread_attr_t *__restrict -+ __attr, void **__restrict __stackaddr) -+ __THROW __nonnull ((1, 2)) __attribute_deprecated__; -+ -+/* Set the starting address of the stack of the thread to be created. -+ Depending on whether the stack grows up or down the value must either -+ be higher or lower than all the address in the memory block. The -+ minimal size of the block must be PTHREAD_STACK_MIN. */ -+extern int pthread_attr_setstackaddr (pthread_attr_t *__attr, -+ void *__stackaddr) -+ __THROW __nonnull ((1)) __attribute_deprecated__; -+ -+/* Return the currently used minimal stack size. */ -+extern int pthread_attr_getstacksize (const pthread_attr_t *__restrict -+ __attr, size_t *__restrict __stacksize) -+ __THROW __nonnull ((1, 2)); -+ -+/* Add information about the minimum stack size needed for the thread -+ to be started. This size must never be less than PTHREAD_STACK_MIN -+ and must also not exceed the system limits. */ -+extern int pthread_attr_setstacksize (pthread_attr_t *__attr, -+ size_t __stacksize) -+ __THROW __nonnull ((1)); -+ -+#ifdef __USE_XOPEN2K -+/* Return the previously set address for the stack. */ -+extern int pthread_attr_getstack (const pthread_attr_t *__restrict __attr, -+ void **__restrict __stackaddr, -+ size_t *__restrict __stacksize) -+ __THROW __nonnull ((1, 2, 3)); -+ -+/* The following two interfaces are intended to replace the last two. They -+ require setting the address as well as the size since only setting the -+ address will make the implementation on some architectures impossible. */ -+extern int pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr, -+ size_t __stacksize) __THROW __nonnull ((1)); -+#endif -+ -+#ifdef __USE_GNU -+/* Thread created with attribute ATTR will be limited to run only on -+ the processors represented in CPUSET. */ -+extern int pthread_attr_setaffinity_np (pthread_attr_t *__attr, -+ size_t __cpusetsize, -+ const cpu_set_t *__cpuset) -+ __THROW __nonnull ((1, 3)); -+ -+/* Get bit set in CPUSET representing the processors threads created with -+ ATTR can run on. */ -+extern int pthread_attr_getaffinity_np (const pthread_attr_t *__attr, -+ size_t __cpusetsize, -+ cpu_set_t *__cpuset) -+ __THROW __nonnull ((1, 3)); -+ -+/* Get the default attributes used by pthread_create in this process. */ -+extern int pthread_getattr_default_np (pthread_attr_t *__attr) -+ __THROW __nonnull ((1)); -+ -+/* Set the default attributes to be used by pthread_create in this -+ process. */ -+extern int pthread_setattr_default_np (const pthread_attr_t *__attr) -+ __THROW __nonnull ((1)); -+ -+/* Initialize thread attribute *ATTR with attributes corresponding to the -+ already running thread TH. It shall be called on uninitialized ATTR -+ and destroyed with pthread_attr_destroy when no longer needed. */ -+extern int pthread_getattr_np (pthread_t __th, pthread_attr_t *__attr) -+ __THROW __nonnull ((2)); -+#endif -+ -+ -+/* Functions for scheduling control. */ -+ -+/* Set the scheduling parameters for TARGET_THREAD according to POLICY -+ and *PARAM. */ -+extern int pthread_setschedparam (pthread_t __target_thread, int __policy, -+ const struct sched_param *__param) -+ __THROW __nonnull ((3)); -+ -+/* Return in *POLICY and *PARAM the scheduling parameters for TARGET_THREAD. */ -+extern int pthread_getschedparam (pthread_t __target_thread, -+ int *__restrict __policy, -+ struct sched_param *__restrict __param) -+ __THROW __nonnull ((2, 3)); -+ -+/* Set the scheduling priority for TARGET_THREAD. */ -+extern int pthread_setschedprio (pthread_t __target_thread, int __prio) -+ __THROW; -+ -+ -+#ifdef __USE_GNU -+/* Get thread name visible in the kernel and its interfaces. */ -+extern int pthread_getname_np (pthread_t __target_thread, char *__buf, -+ size_t __buflen) -+ __THROW __nonnull ((2)); -+ -+/* Set thread name visible in the kernel and its interfaces. */ -+extern int pthread_setname_np (pthread_t __target_thread, const char *__name) -+ __THROW __nonnull ((2)); -+#endif -+ -+ -+#ifdef __USE_UNIX98 -+/* Determine level of concurrency. */ -+extern int pthread_getconcurrency (void) __THROW; -+ -+/* Set new concurrency level to LEVEL. */ -+extern int pthread_setconcurrency (int __level) __THROW; -+#endif -+ -+#ifdef __USE_GNU -+/* Yield the processor to another thread or process. -+ This function is similar to the POSIX `sched_yield' function but -+ might be differently implemented in the case of a m-on-n thread -+ implementation. */ -+extern int pthread_yield (void) __THROW; -+ -+ -+/* Limit specified thread TH to run only on the processors represented -+ in CPUSET. */ -+extern int pthread_setaffinity_np (pthread_t __th, size_t __cpusetsize, -+ const cpu_set_t *__cpuset) -+ __THROW __nonnull ((3)); -+ -+/* Get bit set in CPUSET representing the processors TH can run on. */ -+extern int pthread_getaffinity_np (pthread_t __th, size_t __cpusetsize, -+ cpu_set_t *__cpuset) -+ __THROW __nonnull ((3)); -+#endif -+ -+ -+/* Functions for handling initialization. */ -+ -+/* Guarantee that the initialization function INIT_ROUTINE will be called -+ only once, even if pthread_once is executed several times with the -+ same ONCE_CONTROL argument. ONCE_CONTROL must point to a static or -+ extern variable initialized to PTHREAD_ONCE_INIT. -+ -+ The initialization functions might throw exception which is why -+ this function is not marked with __THROW. */ -+extern int pthread_once (pthread_once_t *__once_control, -+ void (*__init_routine) (void)) __nonnull ((1, 2)); -+ -+ -+/* Functions for handling cancellation. -+ -+ Note that these functions are explicitly not marked to not throw an -+ exception in C++ code. If cancellation is implemented by unwinding -+ this is necessary to have the compiler generate the unwind information. */ -+ -+/* Set cancelability state of current thread to STATE, returning old -+ state in *OLDSTATE if OLDSTATE is not NULL. */ -+extern int pthread_setcancelstate (int __state, int *__oldstate); -+ -+/* Set cancellation state of current thread to TYPE, returning the old -+ type in *OLDTYPE if OLDTYPE is not NULL. */ -+extern int pthread_setcanceltype (int __type, int *__oldtype); -+ -+/* Cancel THREAD immediately or at the next possibility. */ -+extern int pthread_cancel (pthread_t __th); -+ -+/* Test for pending cancellation for the current thread and terminate -+ the thread as per pthread_exit(PTHREAD_CANCELED) if it has been -+ cancelled. */ -+extern void pthread_testcancel (void); -+ -+ -+/* Cancellation handling with integration into exception handling. */ -+ -+typedef struct -+{ -+ struct -+ { -+ __jmp_buf __cancel_jmp_buf; -+ int __mask_was_saved; -+ } __cancel_jmp_buf[1]; -+ void *__pad[4]; -+} __pthread_unwind_buf_t __attribute__ ((__aligned__)); -+ -+/* No special attributes by default. */ -+#ifndef __cleanup_fct_attribute -+# define __cleanup_fct_attribute -+#endif -+ -+ -+/* Structure to hold the cleanup handler information. */ -+struct __pthread_cleanup_frame -+{ -+ void (*__cancel_routine) (void *); -+ void *__cancel_arg; -+ int __do_it; -+ int __cancel_type; -+}; -+ -+#if defined __GNUC__ && defined __EXCEPTIONS -+# ifdef __cplusplus -+/* Class to handle cancellation handler invocation. */ -+class __pthread_cleanup_class -+{ -+ void (*__cancel_routine) (void *); -+ void *__cancel_arg; -+ int __do_it; -+ int __cancel_type; -+ -+ public: -+ __pthread_cleanup_class (void (*__fct) (void *), void *__arg) -+ : __cancel_routine (__fct), __cancel_arg (__arg), __do_it (1) { } -+ ~__pthread_cleanup_class () { if (__do_it) __cancel_routine (__cancel_arg); } -+ void __setdoit (int __newval) { __do_it = __newval; } -+ void __defer () { pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, -+ &__cancel_type); } -+ void __restore () const { pthread_setcanceltype (__cancel_type, 0); } -+}; -+ -+/* Install a cleanup handler: ROUTINE will be called with arguments ARG -+ when the thread is canceled or calls pthread_exit. ROUTINE will also -+ be called with arguments ARG when the matching pthread_cleanup_pop -+ is executed with non-zero EXECUTE argument. -+ -+ pthread_cleanup_push and pthread_cleanup_pop are macros and must always -+ be used in matching pairs at the same nesting level of braces. */ -+# define pthread_cleanup_push(routine, arg) \ -+ do { \ -+ __pthread_cleanup_class __clframe (routine, arg) -+ -+/* Remove a cleanup handler installed by the matching pthread_cleanup_push. -+ If EXECUTE is non-zero, the handler function is called. */ -+# define pthread_cleanup_pop(execute) \ -+ __clframe.__setdoit (execute); \ -+ } while (0) -+ -+# ifdef __USE_GNU -+/* Install a cleanup handler as pthread_cleanup_push does, but also -+ saves the current cancellation type and sets it to deferred -+ cancellation. */ -+# define pthread_cleanup_push_defer_np(routine, arg) \ -+ do { \ -+ __pthread_cleanup_class __clframe (routine, arg); \ -+ __clframe.__defer () -+ -+/* Remove a cleanup handler as pthread_cleanup_pop does, but also -+ restores the cancellation type that was in effect when the matching -+ pthread_cleanup_push_defer was called. */ -+# define pthread_cleanup_pop_restore_np(execute) \ -+ __clframe.__restore (); \ -+ __clframe.__setdoit (execute); \ -+ } while (0) -+# endif -+# else -+/* Function called to call the cleanup handler. As an extern inline -+ function the compiler is free to decide inlining the change when -+ needed or fall back on the copy which must exist somewhere -+ else. */ -+__extern_inline void -+__pthread_cleanup_routine (struct __pthread_cleanup_frame *__frame) -+{ -+ if (__frame->__do_it) -+ __frame->__cancel_routine (__frame->__cancel_arg); -+} -+ -+/* Install a cleanup handler: ROUTINE will be called with arguments ARG -+ when the thread is canceled or calls pthread_exit. ROUTINE will also -+ be called with arguments ARG when the matching pthread_cleanup_pop -+ is executed with non-zero EXECUTE argument. -+ -+ pthread_cleanup_push and pthread_cleanup_pop are macros and must always -+ be used in matching pairs at the same nesting level of braces. */ -+# define pthread_cleanup_push(routine, arg) \ -+ do { \ -+ struct __pthread_cleanup_frame __clframe \ -+ __attribute__ ((__cleanup__ (__pthread_cleanup_routine))) \ -+ = { .__cancel_routine = (routine), .__cancel_arg = (arg), \ -+ .__do_it = 1 }; -+ -+/* Remove a cleanup handler installed by the matching pthread_cleanup_push. -+ If EXECUTE is non-zero, the handler function is called. */ -+# define pthread_cleanup_pop(execute) \ -+ __clframe.__do_it = (execute); \ -+ } while (0) -+ -+# ifdef __USE_GNU -+/* Install a cleanup handler as pthread_cleanup_push does, but also -+ saves the current cancellation type and sets it to deferred -+ cancellation. */ -+# define pthread_cleanup_push_defer_np(routine, arg) \ -+ do { \ -+ struct __pthread_cleanup_frame __clframe \ -+ __attribute__ ((__cleanup__ (__pthread_cleanup_routine))) \ -+ = { .__cancel_routine = (routine), .__cancel_arg = (arg), \ -+ .__do_it = 1 }; \ -+ (void) pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, \ -+ &__clframe.__cancel_type) -+ -+/* Remove a cleanup handler as pthread_cleanup_pop does, but also -+ restores the cancellation type that was in effect when the matching -+ pthread_cleanup_push_defer was called. */ -+# define pthread_cleanup_pop_restore_np(execute) \ -+ (void) pthread_setcanceltype (__clframe.__cancel_type, NULL); \ -+ __clframe.__do_it = (execute); \ -+ } while (0) -+# endif -+# endif -+#else -+/* Install a cleanup handler: ROUTINE will be called with arguments ARG -+ when the thread is canceled or calls pthread_exit. ROUTINE will also -+ be called with arguments ARG when the matching pthread_cleanup_pop -+ is executed with non-zero EXECUTE argument. -+ -+ pthread_cleanup_push and pthread_cleanup_pop are macros and must always -+ be used in matching pairs at the same nesting level of braces. */ -+# define pthread_cleanup_push(routine, arg) \ -+ do { \ -+ __pthread_unwind_buf_t __cancel_buf; \ -+ void (*__cancel_routine) (void *) = (routine); \ -+ void *__cancel_arg = (arg); \ -+ int __not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) (void *) \ -+ __cancel_buf.__cancel_jmp_buf, 0); \ -+ if (__glibc_unlikely (__not_first_call)) \ -+ { \ -+ __cancel_routine (__cancel_arg); \ -+ __pthread_unwind_next (&__cancel_buf); \ -+ /* NOTREACHED */ \ -+ } \ -+ \ -+ __pthread_register_cancel (&__cancel_buf); \ -+ do { -+extern void __pthread_register_cancel (__pthread_unwind_buf_t *__buf) -+ __cleanup_fct_attribute; -+ -+/* Remove a cleanup handler installed by the matching pthread_cleanup_push. -+ If EXECUTE is non-zero, the handler function is called. */ -+# define pthread_cleanup_pop(execute) \ -+ do { } while (0);/* Empty to allow label before pthread_cleanup_pop. */\ -+ } while (0); \ -+ __pthread_unregister_cancel (&__cancel_buf); \ -+ if (execute) \ -+ __cancel_routine (__cancel_arg); \ -+ } while (0) -+extern void __pthread_unregister_cancel (__pthread_unwind_buf_t *__buf) -+ __cleanup_fct_attribute; -+ -+# ifdef __USE_GNU -+/* Install a cleanup handler as pthread_cleanup_push does, but also -+ saves the current cancellation type and sets it to deferred -+ cancellation. */ -+# define pthread_cleanup_push_defer_np(routine, arg) \ -+ do { \ -+ __pthread_unwind_buf_t __cancel_buf; \ -+ void (*__cancel_routine) (void *) = (routine); \ -+ void *__cancel_arg = (arg); \ -+ int __not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) (void *) \ -+ __cancel_buf.__cancel_jmp_buf, 0); \ -+ if (__glibc_unlikely (__not_first_call)) \ -+ { \ -+ __cancel_routine (__cancel_arg); \ -+ __pthread_unwind_next (&__cancel_buf); \ -+ /* NOTREACHED */ \ -+ } \ -+ \ -+ __pthread_register_cancel_defer (&__cancel_buf); \ -+ do { -+extern void __pthread_register_cancel_defer (__pthread_unwind_buf_t *__buf) -+ __cleanup_fct_attribute; -+ -+/* Remove a cleanup handler as pthread_cleanup_pop does, but also -+ restores the cancellation type that was in effect when the matching -+ pthread_cleanup_push_defer was called. */ -+# define pthread_cleanup_pop_restore_np(execute) \ -+ do { } while (0);/* Empty to allow label before pthread_cleanup_pop. */\ -+ } while (0); \ -+ __pthread_unregister_cancel_restore (&__cancel_buf); \ -+ if (execute) \ -+ __cancel_routine (__cancel_arg); \ -+ } while (0) -+extern void __pthread_unregister_cancel_restore (__pthread_unwind_buf_t *__buf) -+ __cleanup_fct_attribute; -+# endif -+ -+/* Internal interface to initiate cleanup. */ -+extern void __pthread_unwind_next (__pthread_unwind_buf_t *__buf) -+ __cleanup_fct_attribute __attribute__ ((__noreturn__)) -+# ifndef SHARED -+ __attribute__ ((__weak__)) -+# endif -+ ; -+#endif -+ -+/* Function used in the macros. */ -+struct __jmp_buf_tag; -+extern int __sigsetjmp (struct __jmp_buf_tag *__env, int __savemask) __THROWNL; -+ -+ -+/* Mutex handling. */ -+ -+/* Initialize a mutex. */ -+extern int pthread_mutex_init (pthread_mutex_t *__mutex, -+ const pthread_mutexattr_t *__mutexattr) -+ __THROW __nonnull ((1)); -+ -+/* Destroy a mutex. */ -+extern int pthread_mutex_destroy (pthread_mutex_t *__mutex) -+ __THROW __nonnull ((1)); -+ -+/* Try locking a mutex. */ -+extern int pthread_mutex_trylock (pthread_mutex_t *__mutex) -+ __THROWNL __nonnull ((1)); -+ -+/* Lock a mutex. */ -+extern int pthread_mutex_lock (pthread_mutex_t *__mutex) -+ __THROWNL __nonnull ((1)); -+ -+#ifdef __USE_XOPEN2K -+/* Wait until lock becomes available, or specified time passes. */ -+extern int pthread_mutex_timedlock (pthread_mutex_t *__restrict __mutex, -+ const struct timespec *__restrict -+ __abstime) __THROWNL __nonnull ((1, 2)); -+#endif -+ -+#ifdef __USE_GNU -+extern int pthread_mutex_clocklock (pthread_mutex_t *__restrict __mutex, -+ clockid_t __clockid, -+ const struct timespec *__restrict -+ __abstime) __THROWNL __nonnull ((1, 3)); -+#endif -+ -+/* Unlock a mutex. */ -+extern int pthread_mutex_unlock (pthread_mutex_t *__mutex) -+ __THROWNL __nonnull ((1)); -+ -+ -+/* Get the priority ceiling of MUTEX. */ -+extern int pthread_mutex_getprioceiling (const pthread_mutex_t * -+ __restrict __mutex, -+ int *__restrict __prioceiling) -+ __THROW __nonnull ((1, 2)); -+ -+/* Set the priority ceiling of MUTEX to PRIOCEILING, return old -+ priority ceiling value in *OLD_CEILING. */ -+extern int pthread_mutex_setprioceiling (pthread_mutex_t *__restrict __mutex, -+ int __prioceiling, -+ int *__restrict __old_ceiling) -+ __THROW __nonnull ((1, 3)); -+ -+ -+#ifdef __USE_XOPEN2K8 -+/* Declare the state protected by MUTEX as consistent. */ -+extern int pthread_mutex_consistent (pthread_mutex_t *__mutex) -+ __THROW __nonnull ((1)); -+# ifdef __USE_GNU -+extern int pthread_mutex_consistent_np (pthread_mutex_t *__mutex) -+ __THROW __nonnull ((1)); -+# endif -+#endif -+ -+ -+/* Functions for handling mutex attributes. */ -+ -+/* Initialize mutex attribute object ATTR with default attributes -+ (kind is PTHREAD_MUTEX_TIMED_NP). */ -+extern int pthread_mutexattr_init (pthread_mutexattr_t *__attr) -+ __THROW __nonnull ((1)); -+ -+/* Destroy mutex attribute object ATTR. */ -+extern int pthread_mutexattr_destroy (pthread_mutexattr_t *__attr) -+ __THROW __nonnull ((1)); -+ -+/* Get the process-shared flag of the mutex attribute ATTR. */ -+extern int pthread_mutexattr_getpshared (const pthread_mutexattr_t * -+ __restrict __attr, -+ int *__restrict __pshared) -+ __THROW __nonnull ((1, 2)); -+ -+/* Set the process-shared flag of the mutex attribute ATTR. */ -+extern int pthread_mutexattr_setpshared (pthread_mutexattr_t *__attr, -+ int __pshared) -+ __THROW __nonnull ((1)); -+ -+#if defined __USE_UNIX98 || defined __USE_XOPEN2K8 -+/* Return in *KIND the mutex kind attribute in *ATTR. */ -+extern int pthread_mutexattr_gettype (const pthread_mutexattr_t *__restrict -+ __attr, int *__restrict __kind) -+ __THROW __nonnull ((1, 2)); -+ -+/* Set the mutex kind attribute in *ATTR to KIND (either PTHREAD_MUTEX_NORMAL, -+ PTHREAD_MUTEX_RECURSIVE, PTHREAD_MUTEX_ERRORCHECK, or -+ PTHREAD_MUTEX_DEFAULT). */ -+extern int pthread_mutexattr_settype (pthread_mutexattr_t *__attr, int __kind) -+ __THROW __nonnull ((1)); -+#endif -+ -+/* Return in *PROTOCOL the mutex protocol attribute in *ATTR. */ -+extern int pthread_mutexattr_getprotocol (const pthread_mutexattr_t * -+ __restrict __attr, -+ int *__restrict __protocol) -+ __THROW __nonnull ((1, 2)); -+ -+/* Set the mutex protocol attribute in *ATTR to PROTOCOL (either -+ PTHREAD_PRIO_NONE, PTHREAD_PRIO_INHERIT, or PTHREAD_PRIO_PROTECT). */ -+extern int pthread_mutexattr_setprotocol (pthread_mutexattr_t *__attr, -+ int __protocol) -+ __THROW __nonnull ((1)); -+ -+/* Return in *PRIOCEILING the mutex prioceiling attribute in *ATTR. */ -+extern int pthread_mutexattr_getprioceiling (const pthread_mutexattr_t * -+ __restrict __attr, -+ int *__restrict __prioceiling) -+ __THROW __nonnull ((1, 2)); -+ -+/* Set the mutex prioceiling attribute in *ATTR to PRIOCEILING. */ -+extern int pthread_mutexattr_setprioceiling (pthread_mutexattr_t *__attr, -+ int __prioceiling) -+ __THROW __nonnull ((1)); -+ -+#ifdef __USE_XOPEN2K -+/* Get the robustness flag of the mutex attribute ATTR. */ -+extern int pthread_mutexattr_getrobust (const pthread_mutexattr_t *__attr, -+ int *__robustness) -+ __THROW __nonnull ((1, 2)); -+# ifdef __USE_GNU -+extern int pthread_mutexattr_getrobust_np (const pthread_mutexattr_t *__attr, -+ int *__robustness) -+ __THROW __nonnull ((1, 2)); -+# endif -+ -+/* Set the robustness flag of the mutex attribute ATTR. */ -+extern int pthread_mutexattr_setrobust (pthread_mutexattr_t *__attr, -+ int __robustness) -+ __THROW __nonnull ((1)); -+# ifdef __USE_GNU -+extern int pthread_mutexattr_setrobust_np (pthread_mutexattr_t *__attr, -+ int __robustness) -+ __THROW __nonnull ((1)); -+# endif -+#endif -+ -+ -+#if defined __USE_UNIX98 || defined __USE_XOPEN2K -+/* Functions for handling read-write locks. */ -+ -+/* Initialize read-write lock RWLOCK using attributes ATTR, or use -+ the default values if later is NULL. */ -+extern int pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock, -+ const pthread_rwlockattr_t *__restrict -+ __attr) __THROW __nonnull ((1)); -+ -+/* Destroy read-write lock RWLOCK. */ -+extern int pthread_rwlock_destroy (pthread_rwlock_t *__rwlock) -+ __THROW __nonnull ((1)); -+ -+/* Acquire read lock for RWLOCK. */ -+extern int pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock) -+ __THROWNL __nonnull ((1)); -+ -+/* Try to acquire read lock for RWLOCK. */ -+extern int pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock) -+ __THROWNL __nonnull ((1)); -+ -+# ifdef __USE_XOPEN2K -+/* Try to acquire read lock for RWLOCK or return after specfied time. */ -+extern int pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock, -+ const struct timespec *__restrict -+ __abstime) __THROWNL __nonnull ((1, 2)); -+# endif -+ -+# ifdef __USE_GNU -+extern int pthread_rwlock_clockrdlock (pthread_rwlock_t *__restrict __rwlock, -+ clockid_t __clockid, -+ const struct timespec *__restrict -+ __abstime) __THROWNL __nonnull ((1, 3)); -+# endif -+ -+/* Acquire write lock for RWLOCK. */ -+extern int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock) -+ __THROWNL __nonnull ((1)); -+ -+/* Try to acquire write lock for RWLOCK. */ -+extern int pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock) -+ __THROWNL __nonnull ((1)); -+ -+# ifdef __USE_XOPEN2K -+/* Try to acquire write lock for RWLOCK or return after specfied time. */ -+extern int pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock, -+ const struct timespec *__restrict -+ __abstime) __THROWNL __nonnull ((1, 2)); -+# endif -+ -+# ifdef __USE_GNU -+extern int pthread_rwlock_clockwrlock (pthread_rwlock_t *__restrict __rwlock, -+ clockid_t __clockid, -+ const struct timespec *__restrict -+ __abstime) __THROWNL __nonnull ((1, 3)); -+# endif -+ -+/* Unlock RWLOCK. */ -+extern int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock) -+ __THROWNL __nonnull ((1)); -+ -+ -+/* Functions for handling read-write lock attributes. */ -+ -+/* Initialize attribute object ATTR with default values. */ -+extern int pthread_rwlockattr_init (pthread_rwlockattr_t *__attr) -+ __THROW __nonnull ((1)); -+ -+/* Destroy attribute object ATTR. */ -+extern int pthread_rwlockattr_destroy (pthread_rwlockattr_t *__attr) -+ __THROW __nonnull ((1)); -+ -+/* Return current setting of process-shared attribute of ATTR in PSHARED. */ -+extern int pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * -+ __restrict __attr, -+ int *__restrict __pshared) -+ __THROW __nonnull ((1, 2)); -+ -+/* Set process-shared attribute of ATTR to PSHARED. */ -+extern int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *__attr, -+ int __pshared) -+ __THROW __nonnull ((1)); -+ -+/* Return current setting of reader/writer preference. */ -+extern int pthread_rwlockattr_getkind_np (const pthread_rwlockattr_t * -+ __restrict __attr, -+ int *__restrict __pref) -+ __THROW __nonnull ((1, 2)); -+ -+/* Set reader/write preference. */ -+extern int pthread_rwlockattr_setkind_np (pthread_rwlockattr_t *__attr, -+ int __pref) __THROW __nonnull ((1)); -+#endif -+ -+ -+/* Functions for handling conditional variables. */ -+ -+/* Initialize condition variable COND using attributes ATTR, or use -+ the default values if later is NULL. */ -+extern int pthread_cond_init (pthread_cond_t *__restrict __cond, -+ const pthread_condattr_t *__restrict __cond_attr) -+ __THROW __nonnull ((1)); -+ -+/* Destroy condition variable COND. */ -+extern int pthread_cond_destroy (pthread_cond_t *__cond) -+ __THROW __nonnull ((1)); -+ -+/* Wake up one thread waiting for condition variable COND. */ -+extern int pthread_cond_signal (pthread_cond_t *__cond) -+ __THROWNL __nonnull ((1)); -+ -+/* Wake up all threads waiting for condition variables COND. */ -+extern int pthread_cond_broadcast (pthread_cond_t *__cond) -+ __THROWNL __nonnull ((1)); -+ -+/* Wait for condition variable COND to be signaled or broadcast. -+ MUTEX is assumed to be locked before. -+ -+ This function is a cancellation point and therefore not marked with -+ __THROW. */ -+extern int pthread_cond_wait (pthread_cond_t *__restrict __cond, -+ pthread_mutex_t *__restrict __mutex) -+ __nonnull ((1, 2)); -+ -+/* Wait for condition variable COND to be signaled or broadcast until -+ ABSTIME. MUTEX is assumed to be locked before. ABSTIME is an -+ absolute time specification; zero is the beginning of the epoch -+ (00:00:00 GMT, January 1, 1970). -+ -+ This function is a cancellation point and therefore not marked with -+ __THROW. */ -+extern int pthread_cond_timedwait (pthread_cond_t *__restrict __cond, -+ pthread_mutex_t *__restrict __mutex, -+ const struct timespec *__restrict __abstime) -+ __nonnull ((1, 2, 3)); -+ -+# ifdef __USE_GNU -+/* Wait for condition variable COND to be signaled or broadcast until -+ ABSTIME measured by the specified clock. MUTEX is assumed to be -+ locked before. CLOCK is the clock to use. ABSTIME is an absolute -+ time specification against CLOCK's epoch. -+ -+ This function is a cancellation point and therefore not marked with -+ __THROW. */ -+extern int pthread_cond_clockwait (pthread_cond_t *__restrict __cond, -+ pthread_mutex_t *__restrict __mutex, -+ __clockid_t __clock_id, -+ const struct timespec *__restrict __abstime) -+ __nonnull ((1, 2, 4)); -+# endif -+ -+/* Functions for handling condition variable attributes. */ -+ -+/* Initialize condition variable attribute ATTR. */ -+extern int pthread_condattr_init (pthread_condattr_t *__attr) -+ __THROW __nonnull ((1)); -+ -+/* Destroy condition variable attribute ATTR. */ -+extern int pthread_condattr_destroy (pthread_condattr_t *__attr) -+ __THROW __nonnull ((1)); -+ -+/* Get the process-shared flag of the condition variable attribute ATTR. */ -+extern int pthread_condattr_getpshared (const pthread_condattr_t * -+ __restrict __attr, -+ int *__restrict __pshared) -+ __THROW __nonnull ((1, 2)); -+ -+/* Set the process-shared flag of the condition variable attribute ATTR. */ -+extern int pthread_condattr_setpshared (pthread_condattr_t *__attr, -+ int __pshared) __THROW __nonnull ((1)); -+ -+#ifdef __USE_XOPEN2K -+/* Get the clock selected for the condition variable attribute ATTR. */ -+extern int pthread_condattr_getclock (const pthread_condattr_t * -+ __restrict __attr, -+ __clockid_t *__restrict __clock_id) -+ __THROW __nonnull ((1, 2)); -+ -+/* Set the clock selected for the condition variable attribute ATTR. */ -+extern int pthread_condattr_setclock (pthread_condattr_t *__attr, -+ __clockid_t __clock_id) -+ __THROW __nonnull ((1)); -+#endif -+ -+ -+#ifdef __USE_XOPEN2K -+/* Functions to handle spinlocks. */ -+ -+/* Initialize the spinlock LOCK. If PSHARED is nonzero the spinlock can -+ be shared between different processes. */ -+extern int pthread_spin_init (pthread_spinlock_t *__lock, int __pshared) -+ __THROW __nonnull ((1)); -+ -+/* Destroy the spinlock LOCK. */ -+extern int pthread_spin_destroy (pthread_spinlock_t *__lock) -+ __THROW __nonnull ((1)); -+ -+/* Wait until spinlock LOCK is retrieved. */ -+extern int pthread_spin_lock (pthread_spinlock_t *__lock) -+ __THROWNL __nonnull ((1)); -+ -+/* Try to lock spinlock LOCK. */ -+extern int pthread_spin_trylock (pthread_spinlock_t *__lock) -+ __THROWNL __nonnull ((1)); -+ -+/* Release spinlock LOCK. */ -+extern int pthread_spin_unlock (pthread_spinlock_t *__lock) -+ __THROWNL __nonnull ((1)); -+ -+ -+/* Functions to handle barriers. */ -+ -+/* Initialize BARRIER with the attributes in ATTR. The barrier is -+ opened when COUNT waiters arrived. */ -+extern int pthread_barrier_init (pthread_barrier_t *__restrict __barrier, -+ const pthread_barrierattr_t *__restrict -+ __attr, unsigned int __count) -+ __THROW __nonnull ((1)); -+ -+/* Destroy a previously dynamically initialized barrier BARRIER. */ -+extern int pthread_barrier_destroy (pthread_barrier_t *__barrier) -+ __THROW __nonnull ((1)); -+ -+/* Wait on barrier BARRIER. */ -+extern int pthread_barrier_wait (pthread_barrier_t *__barrier) -+ __THROWNL __nonnull ((1)); -+ -+ -+/* Initialize barrier attribute ATTR. */ -+extern int pthread_barrierattr_init (pthread_barrierattr_t *__attr) -+ __THROW __nonnull ((1)); -+ -+/* Destroy previously dynamically initialized barrier attribute ATTR. */ -+extern int pthread_barrierattr_destroy (pthread_barrierattr_t *__attr) -+ __THROW __nonnull ((1)); -+ -+/* Get the process-shared flag of the barrier attribute ATTR. */ -+extern int pthread_barrierattr_getpshared (const pthread_barrierattr_t * -+ __restrict __attr, -+ int *__restrict __pshared) -+ __THROW __nonnull ((1, 2)); -+ -+/* Set the process-shared flag of the barrier attribute ATTR. */ -+extern int pthread_barrierattr_setpshared (pthread_barrierattr_t *__attr, -+ int __pshared) -+ __THROW __nonnull ((1)); -+#endif -+ -+ -+/* Functions for handling thread-specific data. */ -+ -+/* Create a key value identifying a location in the thread-specific -+ data area. Each thread maintains a distinct thread-specific data -+ area. DESTR_FUNCTION, if non-NULL, is called with the value -+ associated to that key when the key is destroyed. -+ DESTR_FUNCTION is not called if the value associated is NULL when -+ the key is destroyed. */ -+extern int pthread_key_create (pthread_key_t *__key, -+ void (*__destr_function) (void *)) -+ __THROW __nonnull ((1)); -+ -+/* Destroy KEY. */ -+extern int pthread_key_delete (pthread_key_t __key) __THROW; -+ -+/* Return current value of the thread-specific data slot identified by KEY. */ -+extern void *pthread_getspecific (pthread_key_t __key) __THROW; -+ -+/* Store POINTER in the thread-specific data slot identified by KEY. */ -+extern int pthread_setspecific (pthread_key_t __key, -+ const void *__pointer) __THROW ; -+ -+ -+#ifdef __USE_XOPEN2K -+/* Get ID of CPU-time clock for thread THREAD_ID. */ -+extern int pthread_getcpuclockid (pthread_t __thread_id, -+ __clockid_t *__clock_id) -+ __THROW __nonnull ((2)); -+#endif -+ -+ -+/* Install handlers to be called when a new process is created with FORK. -+ The PREPARE handler is called in the parent process just before performing -+ FORK. The PARENT handler is called in the parent process just after FORK. -+ The CHILD handler is called in the child process. Each of the three -+ handlers can be NULL, meaning that no handler needs to be called at that -+ point. -+ PTHREAD_ATFORK can be called several times, in which case the PREPARE -+ handlers are called in LIFO order (last added with PTHREAD_ATFORK, -+ first called before FORK), and the PARENT and CHILD handlers are called -+ in FIFO (first added, first called). */ -+ -+extern int pthread_atfork (void (*__prepare) (void), -+ void (*__parent) (void), -+ void (*__child) (void)) __THROW; -+ -+ -+#ifdef __USE_EXTERN_INLINES -+/* Optimizations. */ -+__extern_inline int -+__NTH (pthread_equal (pthread_t __thread1, pthread_t __thread2)) -+{ -+ return __thread1 == __thread2; -+} -+#endif -+ -+__END_DECLS -+ -+#endif /* pthread.h */ -diff --git a/nptl_2_17/pthread_cond_broadcast_2_17.c b/nptl_2_17/pthread_cond_broadcast_2_17.c -new file mode 100644 -index 00000000..e1d5f332 ---- /dev/null -+++ b/nptl_2_17/pthread_cond_broadcast_2_17.c -@@ -0,0 +1,94 @@ -+/* Copyright (C) 2003-2020 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Martin Schwidefsky , 2003. -+ -+ 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 -+ . */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include -+ -+int -+__pthread_cond_broadcast (pthread_cond_t *cond) -+{ -+ LIBC_PROBE (cond_broadcast, 1, cond); -+ -+ int pshared = (cond->__data.__mutex == (void *) ~0l) -+ ? LLL_SHARED : LLL_PRIVATE; -+ /* Make sure we are alone. */ -+ lll_lock (cond->__data.__lock, pshared); -+ -+ /* Are there any waiters to be woken? */ -+ if (cond->__data.__total_seq > cond->__data.__wakeup_seq) -+ -+ { -+ /* Yes. Mark them all as woken. */ -+ cond->__data.__wakeup_seq = cond->__data.__total_seq; -+ cond->__data.__woken_seq = cond->__data.__total_seq; -+ cond->__data.__futex = (unsigned int) cond->__data.__total_seq * 2; -+ int futex_val = cond->__data.__futex; -+ /* Signal that a broadcast happened. */ -+ ++cond->__data.__broadcast_seq; -+ -+ /* We are done. */ -+ lll_unlock (cond->__data.__lock, pshared); -+ -+ /* Wake everybody. */ -+ pthread_mutex_t *mut = (pthread_mutex_t *) cond->__data.__mutex; -+ -+ /* Do not use requeue for pshared condvars. */ -+ if (mut == (void *) ~0l -+ || PTHREAD_MUTEX_PSHARED (mut) & PTHREAD_MUTEX_PSHARED_BIT) -+ goto wake_all; -+ -+#if (defined lll_futex_cmp_requeue_pi \ -+ && defined __ASSUME_REQUEUE_PI) -+ if (USE_REQUEUE_PI (mut)) -+ { -+ if (lll_futex_cmp_requeue_pi (&cond->__data.__futex, 1, INT_MAX, -+ &mut->__data.__lock, futex_val, -+ LLL_PRIVATE) == 0) -+ return 0; -+ } -+ else -+#endif -+ /* lll_futex_requeue returns 0 for success and non-zero -+ for errors. */ -+ if (!__builtin_expect (lll_futex_requeue (&cond->__data.__futex, 1, -+ INT_MAX, &mut->__data.__lock, -+ futex_val, LLL_PRIVATE), 0)) -+ return 0; -+ -+wake_all: -+ lll_futex_wake (&cond->__data.__futex, INT_MAX, pshared); -+ return 0; -+ } -+ /* We are done. */ -+ lll_unlock (cond->__data.__lock, pshared); -+ -+ return 0; -+} -+ -+versioned_symbol (libpthread, __pthread_cond_broadcast, pthread_cond_broadcast, -+ GLIBC_2_3_2); -diff --git a/nptl_2_17/pthread_cond_destroy_2_17.c b/nptl_2_17/pthread_cond_destroy_2_17.c -new file mode 100644 -index 00000000..62c8ae72 ---- /dev/null -+++ b/nptl_2_17/pthread_cond_destroy_2_17.c -@@ -0,0 +1,85 @@ -+/* Copyright (C) 2002-2020 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Ulrich Drepper , 2002. -+ -+ 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 -+ . */ -+ -+#include "pthreadP_2_17.h" -+#include -+#include -+#include -+int -+__pthread_cond_destroy (pthread_cond_t *cond) -+{ -+ int pshared = (cond->__data.__mutex == (void *) ~0l) -+ ? LLL_SHARED : LLL_PRIVATE; -+ -+ LIBC_PROBE (cond_destroy, 1, cond); -+ -+ /* Make sure we are alone. */ -+ lll_lock (cond->__data.__lock, pshared); -+ -+ if (cond->__data.__total_seq > cond->__data.__wakeup_seq) -+ { -+ /* If there are still some waiters which have not been -+ woken up, this is an application bug. */ -+ lll_unlock (cond->__data.__lock, pshared); -+ return EBUSY; -+ } -+ -+ /* Tell pthread_cond_*wait that this condvar is being destroyed. */ -+ cond->__data.__total_seq = -1ULL; -+ -+ /* If there are waiters which have been already signalled or -+ broadcasted, but still are using the pthread_cond_t structure, -+ pthread_cond_destroy needs to wait for them. */ -+ unsigned int nwaiters = cond->__data.__nwaiters; -+ -+ if (nwaiters >= (1 << COND_NWAITERS_SHIFT)) -+ -+ { -+ /* Wake everybody on the associated mutex in case there are -+ threads that have been requeued to it. -+ Without this, pthread_cond_destroy could block potentially -+ for a long time or forever, as it would depend on other -+ thread's using the mutex. -+ When all threads waiting on the mutex are woken up, pthread_cond_wait -+ only waits for threads to acquire and release the internal -+ condvar lock. */ -+ if (cond->__data.__mutex != NULL -+ && cond->__data.__mutex != (void *) ~0l) -+ { -+ pthread_mutex_t *mut = (pthread_mutex_t *) cond->__data.__mutex; -+ lll_futex_wake (&mut->__data.__lock, INT_MAX, -+ PTHREAD_MUTEX_PSHARED (mut)); -+ } -+ -+ do -+ { -+ lll_unlock (cond->__data.__lock, pshared); -+ -+ lll_futex_wait (&cond->__data.__nwaiters, nwaiters, pshared); -+ -+ lll_lock (cond->__data.__lock, pshared); -+ -+ nwaiters = cond->__data.__nwaiters; -+ } -+ while (nwaiters >= (1 << COND_NWAITERS_SHIFT)); -+ } -+ -+ return 0; -+} -+versioned_symbol (libpthread, __pthread_cond_destroy, -+ pthread_cond_destroy, GLIBC_2_3_2); -diff --git a/nptl_2_17/pthread_cond_init_2_17.c b/nptl_2_17/pthread_cond_init_2_17.c -new file mode 100644 -index 00000000..7acaa86b ---- /dev/null -+++ b/nptl_2_17/pthread_cond_init_2_17.c -@@ -0,0 +1,50 @@ -+/* Copyright (C) 2002-2020 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Ulrich Drepper , 2002. -+ -+ 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 -+ . */ -+ -+#include "pthreadP_2_17.h" -+#include -+#include -+ -+ -+int -+__pthread_cond_init (pthread_cond_t *cond, const pthread_condattr_t *cond_attr) -+{ -+ ASSERT_TYPE_SIZE (pthread_cond_t, __SIZEOF_PTHREAD_COND_T); -+ -+ struct pthread_condattr *icond_attr = (struct pthread_condattr *) cond_attr; -+ -+ cond->__data.__lock = LLL_LOCK_INITIALIZER; -+ cond->__data.__futex = 0; -+ cond->__data.__nwaiters = (icond_attr != NULL -+ ? ((icond_attr->value >> 1) -+ & ((1 << COND_NWAITERS_SHIFT) - 1)) -+ : CLOCK_REALTIME); -+ cond->__data.__total_seq = 0; -+ cond->__data.__wakeup_seq = 0; -+ cond->__data.__woken_seq = 0; -+ cond->__data.__mutex = (icond_attr == NULL || (icond_attr->value & 1) == 0 -+ ? NULL : (void *) ~0l); -+ cond->__data.__broadcast_seq = 0; -+ -+ -+ LIBC_PROBE (cond_init, 2, cond, cond_attr); -+ -+ return 0; -+} -+versioned_symbol (libpthread, __pthread_cond_init, -+ pthread_cond_init, GLIBC_2_3_2); -diff --git a/nptl_2_17/pthread_cond_signal_2_17.c b/nptl_2_17/pthread_cond_signal_2_17.c -new file mode 100644 -index 00000000..a8053d33 ---- /dev/null -+++ b/nptl_2_17/pthread_cond_signal_2_17.c -@@ -0,0 +1,82 @@ -+/* Copyright (C) 2003-2020 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Martin Schwidefsky , 2003. -+ -+ 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 -+ . */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+ -+int -+__pthread_cond_signal (pthread_cond_t *cond) -+{ -+ int pshared = (cond->__data.__mutex == (void *) ~0l) -+ ? LLL_SHARED : LLL_PRIVATE; -+ -+ LIBC_PROBE (cond_signal, 1, cond); -+ -+ /* Make sure we are alone. */ -+ lll_lock (cond->__data.__lock, pshared); -+ -+ /* Are there any waiters to be woken? */ -+ if (cond->__data.__total_seq > cond->__data.__wakeup_seq) -+ { -+ /* Yes. Mark one of them as woken. */ -+ ++cond->__data.__wakeup_seq; -+ ++cond->__data.__futex; -+ -+#if (defined lll_futex_cmp_requeue_pi \ -+ && defined __ASSUME_REQUEUE_PI) -+ pthread_mutex_t *mut = cond->__data.__mutex; -+ -+ if (USE_REQUEUE_PI (mut) -+ /* This can only really fail with a ENOSYS, since nobody can modify -+ futex while we have the cond_lock. */ -+ && lll_futex_cmp_requeue_pi (&cond->__data.__futex, 1, 0, -+ &mut->__data.__lock, -+ cond->__data.__futex, pshared) == 0) -+ { -+ lll_unlock (cond->__data.__lock, pshared); -+ return 0; -+ } -+ else -+#endif -+ /* Wake one. */ -+ if (! __builtin_expect (lll_futex_wake_unlock (&cond->__data.__futex, -+ 1, 1, -+ &cond->__data.__lock, -+ pshared), 0)) -+ return 0; -+ -+ /* Fallback if neither of them work. */ -+ lll_futex_wake (&cond->__data.__futex, 1, pshared); -+ } -+/* We are done. */ -+ lll_unlock (cond->__data.__lock, pshared); -+ -+ return 0; -+} -+ -+versioned_symbol (libpthread, __pthread_cond_signal, pthread_cond_signal, -+ GLIBC_2_3_2); -diff --git a/nptl_2_17/pthread_cond_timedwait_2_17.c b/nptl_2_17/pthread_cond_timedwait_2_17.c -new file mode 100644 -index 00000000..965d51a1 ---- /dev/null -+++ b/nptl_2_17/pthread_cond_timedwait_2_17.c -@@ -0,0 +1,268 @@ -+/* Copyright (C) 2003-2016 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Martin Schwidefsky , 2003. -+ -+ 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 -+ . */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#ifndef HAVE_CLOCK_GETTIME_VSYSCALL -+# undef INTERNAL_VSYSCALL -+# define INTERNAL_VSYSCALL INTERNAL_SYSCALL -+# undef INLINE_VSYSCALL -+# define INLINE_VSYSCALL INLINE_SYSCALL -+#else -+# include -+#endif -+ -+/* Cleanup handler, defined in pthread_cond_wait.c. */ -+extern void __condvar_cleanup (void *arg) -+ __attribute__ ((visibility ("hidden"))); -+ -+struct _condvar_cleanup_buffer -+{ -+ int oldtype; -+ pthread_cond_t *cond; -+ pthread_mutex_t *mutex; -+ unsigned int bc_seq; -+}; -+ -+int -+__pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, -+ const struct timespec *abstime) -+{ -+ struct _pthread_cleanup_buffer buffer; -+ struct _condvar_cleanup_buffer cbuffer; -+ int result = 0; -+ -+ /* Catch invalid parameters. */ -+ if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) -+ return EINVAL; -+ -+ int pshared = (cond->__data.__mutex == (void *) ~0l) -+ ? LLL_SHARED : LLL_PRIVATE; -+ -+#if (defined lll_futex_timed_wait_requeue_pi \ -+ && defined __ASSUME_REQUEUE_PI) -+ int pi_flag = 0; -+#endif -+ -+ /* Make sure we are alone. */ -+ lll_lock (cond->__data.__lock, pshared); -+ -+ /* Now we can release the mutex. */ -+ int err = __pthread_mutex_unlock_usercnt (mutex, 0); -+ if (err) -+ { -+ lll_unlock (cond->__data.__lock, pshared); -+ return err; -+ } -+ -+ /* We have one new user of the condvar. */ -+ ++cond->__data.__total_seq; -+ ++cond->__data.__futex; -+ cond->__data.__nwaiters += 1 << COND_NWAITERS_SHIFT; -+ -+ /* Work around the fact that the kernel rejects negative timeout values -+ despite them being valid. */ -+ if (__glibc_unlikely (abstime->tv_sec < 0)) -+ goto timeout; -+ -+ /* Remember the mutex we are using here. If there is already a -+ different address store this is a bad user bug. Do not store -+ anything for pshared condvars. */ -+ if (cond->__data.__mutex != (void *) ~0l) -+ cond->__data.__mutex = mutex; -+ -+ /* Prepare structure passed to cancellation handler. */ -+ cbuffer.cond = cond; -+ cbuffer.mutex = mutex; -+ -+ /* Before we block we enable cancellation. Therefore we have to -+ install a cancellation handler. */ -+ __pthread_cleanup_push (&buffer, __condvar_cleanup, &cbuffer); -+ -+ /* The current values of the wakeup counter. The "woken" counter -+ must exceed this value. */ -+ unsigned long long int val; -+ unsigned long long int seq; -+ val = seq = cond->__data.__wakeup_seq; -+ /* Remember the broadcast counter. */ -+ cbuffer.bc_seq = cond->__data.__broadcast_seq; -+ -+ while (1) -+ { -+#if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \ -+ || !defined lll_futex_timed_wait_bitset) -+ struct timespec rt; -+ { -+# ifdef __NR_clock_gettime -+ INTERNAL_SYSCALL_DECL (err); -+ (void) INTERNAL_VSYSCALL (clock_gettime, err, 2, -+ (cond->__data.__nwaiters -+ & ((1 << COND_NWAITERS_SHIFT) - 1)), -+ &rt); -+ /* Convert the absolute timeout value to a relative timeout. */ -+ rt.tv_sec = abstime->tv_sec - rt.tv_sec; -+ rt.tv_nsec = abstime->tv_nsec - rt.tv_nsec; -+# else -+ /* Get the current time. So far we support only one clock. */ -+ struct timeval tv; -+ (void) __gettimeofday (&tv, NULL); -+ -+ /* Convert the absolute timeout value to a relative timeout. */ -+ rt.tv_sec = abstime->tv_sec - tv.tv_sec; -+ rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; -+# endif -+ } -+ if (rt.tv_nsec < 0) -+ { -+ rt.tv_nsec += 1000000000; -+ --rt.tv_sec; -+ } -+ /* Did we already time out? */ -+ if (__glibc_unlikely (rt.tv_sec < 0)) -+ { -+ if (cbuffer.bc_seq != cond->__data.__broadcast_seq) -+ goto bc_out; -+ -+ goto timeout; -+ } -+#endif -+ -+ unsigned int futex_val = cond->__data.__futex; -+ -+ /* Prepare to wait. Release the condvar futex. */ -+ lll_unlock (cond->__data.__lock, pshared); -+ -+ /* Enable asynchronous cancellation. Required by the standard. */ -+ cbuffer.oldtype = __pthread_enable_asynccancel (); -+ -+/* REQUEUE_PI was implemented after FUTEX_CLOCK_REALTIME, so it is sufficient -+ to check just the former. */ -+#if (defined lll_futex_timed_wait_requeue_pi \ -+ && defined __ASSUME_REQUEUE_PI) -+ /* If pi_flag remained 1 then it means that we had the lock and the mutex -+ but a spurious waker raced ahead of us. Give back the mutex before -+ going into wait again. */ -+ if (pi_flag) -+ { -+ __pthread_mutex_cond_lock_adjust (mutex); -+ __pthread_mutex_unlock_usercnt (mutex, 0); -+ } -+ pi_flag = USE_REQUEUE_PI (mutex); -+ -+ if (pi_flag) -+ { -+ unsigned int clockbit = (cond->__data.__nwaiters & 1 -+ ? 0 : FUTEX_CLOCK_REALTIME); -+ err = lll_futex_timed_wait_requeue_pi (&cond->__data.__futex, -+ futex_val, abstime, clockbit, -+ &mutex->__data.__lock, -+ pshared); -+ pi_flag = (err == 0); -+ } -+ else -+#endif -+ -+ { -+#if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \ -+ || !defined lll_futex_timed_wait_bitset) -+ /* Wait until woken by signal or broadcast. */ -+ err = lll_futex_timed_wait (&cond->__data.__futex, -+ futex_val, &rt, pshared); -+#else -+ unsigned int clockbit = (cond->__data.__nwaiters & 1 -+ ? 0 : FUTEX_CLOCK_REALTIME); -+ err = lll_futex_timed_wait_bitset (&cond->__data.__futex, futex_val, -+ abstime, clockbit, pshared); -+#endif -+ } -+ -+ /* Disable asynchronous cancellation. */ -+ __pthread_disable_asynccancel (cbuffer.oldtype); -+ -+ /* We are going to look at shared data again, so get the lock. */ -+ lll_lock (cond->__data.__lock, pshared); -+ -+ /* If a broadcast happened, we are done. */ -+ if (cbuffer.bc_seq != cond->__data.__broadcast_seq) -+ goto bc_out; -+ -+ /* Check whether we are eligible for wakeup. */ -+ val = cond->__data.__wakeup_seq; -+ if (val != seq && cond->__data.__woken_seq != val) -+ break; -+ -+ /* Not woken yet. Maybe the time expired? */ -+ if (__glibc_unlikely (err == -ETIMEDOUT)) -+ { -+ timeout: -+ /* Yep. Adjust the counters. */ -+ ++cond->__data.__wakeup_seq; -+ ++cond->__data.__futex; -+ -+ /* The error value. */ -+ result = ETIMEDOUT; -+ break; -+ } -+ } -+ -+ /* Another thread woken up. */ -+ ++cond->__data.__woken_seq; -+ -+ bc_out: -+ -+ cond->__data.__nwaiters -= 1 << COND_NWAITERS_SHIFT; -+ -+ /* If pthread_cond_destroy was called on this variable already, -+ notify the pthread_cond_destroy caller all waiters have left -+ and it can be successfully destroyed. */ -+ if (cond->__data.__total_seq == -1ULL -+ && cond->__data.__nwaiters < (1 << COND_NWAITERS_SHIFT)) -+ lll_futex_wake (&cond->__data.__nwaiters, 1, pshared); -+ -+ /* We are done with the condvar. */ -+ lll_unlock (cond->__data.__lock, pshared); -+ -+ /* The cancellation handling is back to normal, remove the handler. */ -+ __pthread_cleanup_pop (&buffer, 0); -+ -+ /* Get the mutex before returning. */ -+#if (defined lll_futex_timed_wait_requeue_pi \ -+ && defined __ASSUME_REQUEUE_PI) -+ if (pi_flag) -+ { -+ __pthread_mutex_cond_lock_adjust (mutex); -+ err = 0; -+ } -+ else -+#endif -+ err = __pthread_mutex_cond_lock (mutex); -+ -+ return err ?: result; -+} -+ -+versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait, -+ GLIBC_2_3_2); -diff --git a/nptl_2_17/pthread_cond_wait_2_17.c b/nptl_2_17/pthread_cond_wait_2_17.c -new file mode 100644 -index 00000000..ecd404ad ---- /dev/null -+++ b/nptl_2_17/pthread_cond_wait_2_17.c -@@ -0,0 +1,231 @@ -+/* Copyright (C) 2003-2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Martin Schwidefsky , 2003. -+ -+ 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 -+ . */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+struct _condvar_cleanup_buffer -+{ -+ int oldtype; -+ pthread_cond_t *cond; -+ pthread_mutex_t *mutex; -+ unsigned int bc_seq; -+}; -+ -+void -+__attribute__ ((visibility ("hidden"))) -+__condvar_cleanup (void *arg) -+{ -+ struct _condvar_cleanup_buffer *cbuffer = -+ (struct _condvar_cleanup_buffer *) arg; -+ unsigned int destroying; -+ int pshared = (cbuffer->cond->__data.__mutex == (void *) ~0l) -+ ? LLL_SHARED : LLL_PRIVATE; -+ -+ /* We are going to modify shared data. */ -+ lll_lock (cbuffer->cond->__data.__lock, pshared); -+ -+ if (cbuffer->bc_seq == cbuffer->cond->__data.__broadcast_seq) -+ { -+ /* This thread is not waiting anymore. Adjust the sequence counters -+ * appropriately. We do not increment WAKEUP_SEQ if this would -+ * bump it over the value of TOTAL_SEQ. This can happen if a thread -+ * was woken and then canceled. */ -+ if (cbuffer->cond->__data.__wakeup_seq -+ < cbuffer->cond->__data.__total_seq) -+ { -+ ++cbuffer->cond->__data.__wakeup_seq; -+ ++cbuffer->cond->__data.__futex; -+ } -+ ++cbuffer->cond->__data.__woken_seq; -+ } -+ -+ cbuffer->cond->__data.__nwaiters -= 1 << COND_NWAITERS_SHIFT; -+ -+ /* If pthread_cond_destroy was called on this variable already, -+ * notify the pthread_cond_destroy caller all waiters have left -+ * and it can be successfully destroyed. */ -+ destroying = 0; -+ if (cbuffer->cond->__data.__total_seq == -1ULL -+ && cbuffer->cond->__data.__nwaiters < (1 << COND_NWAITERS_SHIFT)) -+ { -+ lll_futex_wake (&cbuffer->cond->__data.__nwaiters, 1, pshared); -+ destroying = 1; -+ } -+ -+ /* We are done. */ -+ lll_unlock (cbuffer->cond->__data.__lock, pshared); -+ -+ /* Wake everybody to make sure no condvar signal gets lost. */ -+ if (! destroying) -+ lll_futex_wake (&cbuffer->cond->__data.__futex, INT_MAX, pshared); -+ -+ /* Get the mutex before returning unless asynchronous cancellation -+ * is in effect. We don't try to get the mutex if we already own it. */ -+ if (!(USE_REQUEUE_PI (cbuffer->mutex)) -+ || ((cbuffer->mutex->__data.__lock & FUTEX_TID_MASK) -+ != THREAD_GETMEM (THREAD_SELF, tid))) -+ { -+ __pthread_mutex_cond_lock (cbuffer->mutex); -+ } -+ else -+ __pthread_mutex_cond_lock_adjust (cbuffer->mutex); -+} -+ -+int -+__pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) -+{ -+struct _pthread_cleanup_buffer buffer; -+ struct _condvar_cleanup_buffer cbuffer; -+ int err; -+ int pshared = (cond->__data.__mutex == (void *) ~0l) -+ ? LLL_SHARED : LLL_PRIVATE; -+ -+#if (defined lll_futex_wait_requeue_pi \ -+ && defined __ASSUME_REQUEUE_PI) -+ int pi_flag = 0; -+#endif -+ -+ LIBC_PROBE (cond_wait, 2, cond, mutex); -+ /* Make sure we are alone. */ -+ lll_lock (cond->__data.__lock, pshared); -+ -+ /* Now we can release the mutex. */ -+ err = __pthread_mutex_unlock_usercnt (mutex, 0); -+ if (__glibc_unlikely (err)) -+ { -+ lll_unlock (cond->__data.__lock, pshared); -+ return err; -+ } -+ /* We have one new user of the condvar. */ -+ ++cond->__data.__total_seq; -+ ++cond->__data.__futex; -+ cond->__data.__nwaiters += 1 << COND_NWAITERS_SHIFT; -+ -+ /* Remember the mutex we are using here. If there is already a -+ * different address store this is a bad user bug. Do not store -+ * anything for pshared condvars. */ -+ if (cond->__data.__mutex != (void *) ~0l) -+ cond->__data.__mutex = mutex; -+ -+ /* Prepare structure passed to cancellation handler. */ -+ cbuffer.cond = cond; -+ cbuffer.mutex = mutex; -+ -+ /* Before we block we enable cancellation. Therefore we have to -+ * install a cancellation handler. */ -+ __pthread_cleanup_push (&buffer, __condvar_cleanup, &cbuffer); -+ -+ /* The current values of the wakeup counter. The "woken" counter -+ * must exceed this value. */ -+ unsigned long long int val; -+ unsigned long long int seq; -+ val = seq = cond->__data.__wakeup_seq; -+ /* Remember the broadcast counter. */ -+ cbuffer.bc_seq = cond->__data.__broadcast_seq; -+ -+ do -+ { -+ unsigned int futex_val = cond->__data.__futex; -+ /* Prepare to wait. Release the condvar futex. */ -+ lll_unlock (cond->__data.__lock, pshared); -+ -+ /* Enable asynchronous cancellation. Required by the standard. */ -+ cbuffer.oldtype = __pthread_enable_asynccancel (); -+ -+#if (defined lll_futex_wait_requeue_pi \ -+ && defined __ASSUME_REQUEUE_PI) -+ /* If pi_flag remained 1 then it means that we had the lock and the mutex -+ but a spurious waker raced ahead of us. Give back the mutex before -+ going into wait again. */ -+ if (pi_flag) -+ { -+ __pthread_mutex_cond_lock_adjust (mutex); -+ __pthread_mutex_unlock_usercnt (mutex, 0); -+ } -+ pi_flag = USE_REQUEUE_PI (mutex); -+ -+ if (pi_flag) -+ { -+ err = lll_futex_wait_requeue_pi (&cond->__data.__futex, -+ futex_val, &mutex->__data.__lock, -+ pshared); -+ -+ pi_flag = (err == 0); -+ } -+ else -+#endif -+ /* Wait until woken by signal or broadcast. */ -+ lll_futex_wait (&cond->__data.__futex, futex_val, pshared); -+ -+ /* Disable asynchronous cancellation. */ -+ __pthread_disable_asynccancel (cbuffer.oldtype); -+ -+ /* We are going to look at shared data again, so get the lock. */ -+ lll_lock (cond->__data.__lock, pshared); -+ -+ /* If a broadcast happened, we are done. */ -+ if (cbuffer.bc_seq != cond->__data.__broadcast_seq) -+ goto bc_out; -+ -+ /* Check whether we are eligible for wakeup. */ -+ val = cond->__data.__wakeup_seq; -+ } -+ while (val == seq || cond->__data.__woken_seq == val); -+ -+ /* Another thread woken up. */ -+ ++cond->__data.__woken_seq; -+ -+bc_out: -+ cond->__data.__nwaiters -= 1 << COND_NWAITERS_SHIFT; -+ -+ /* If pthread_cond_destroy was called on this varaible already, -+ notify the pthread_cond_destroy caller all waiters have left -+ and it can be successfully destroyed. */ -+ if (cond->__data.__total_seq == -1ULL -+ && cond->__data.__nwaiters < (1 << COND_NWAITERS_SHIFT)) -+ lll_futex_wake (&cond->__data.__nwaiters, 1, pshared); -+ -+ /* We are done with the condvar. */ -+ lll_unlock (cond->__data.__lock, pshared); -+ -+ /* The cancellation handling is back to normal, remove the handler. */ -+ __pthread_cleanup_pop (&buffer, 0); -+ -+ /* Get the mutex before returning. Not needed for PI. */ -+#if (defined lll_futex_wait_requeue_pi \ -+ && defined __ASSUME_REQUEUE_PI) -+ if (pi_flag) -+ { -+ __pthread_mutex_cond_lock_adjust (mutex); -+ return 0; -+ } -+ else -+#endif -+ return __pthread_mutex_cond_lock (mutex); -+} -+ -+versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait, -+ GLIBC_2_3_2); -diff --git a/nptl_2_17/pthread_condattr_getclock_2_17.c b/nptl_2_17/pthread_condattr_getclock_2_17.c -new file mode 100644 -index 00000000..e07b349e ---- /dev/null -+++ b/nptl_2_17/pthread_condattr_getclock_2_17.c -@@ -0,0 +1,28 @@ -+/* Copyright (C) 2003-2020 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Ulrich Drepper , 2003. -+ -+ 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 -+ . */ -+ -+#include "pthreadP_2_17.h" -+ -+ -+int -+pthread_condattr_getclock (const pthread_condattr_t *attr, clockid_t *clock_id) -+{ -+ *clock_id = (((((const struct pthread_condattr *) attr)->value) >> 1) -+ & ((1 << COND_NWAITERS_SHIFT) - 1)); -+ return 0; -+} -diff --git a/nptl_2_17/pthread_condattr_getpshared_2_17.c b/nptl_2_17/pthread_condattr_getpshared_2_17.c -new file mode 100644 -index 00000000..8f4fe2bf ---- /dev/null -+++ b/nptl_2_17/pthread_condattr_getpshared_2_17.c -@@ -0,0 +1,28 @@ -+/* Copyright (C) 2002-2020 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Ulrich Drepper , 2002. -+ -+ 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 -+ . */ -+ -+#include "pthreadP_2_17.h" -+ -+ -+int -+pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared) -+{ -+ *pshared = ((const struct pthread_condattr *) attr)->value & 1; -+ -+ return 0; -+} -diff --git a/nptl_2_17/pthread_condattr_init_2_17.c b/nptl_2_17/pthread_condattr_init_2_17.c -new file mode 100644 -index 00000000..d90ba1e8 ---- /dev/null -+++ b/nptl_2_17/pthread_condattr_init_2_17.c -@@ -0,0 +1,34 @@ -+/* Copyright (C) 2002-2020 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Ulrich Drepper , 2002. -+ -+ 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 -+ . */ -+ -+#include -+#include "pthreadP_2_17.h" -+ -+ -+int -+__pthread_condattr_init (pthread_condattr_t *attr) -+{ -+ ASSERT_TYPE_SIZE (pthread_condattr_t, __SIZEOF_PTHREAD_CONDATTR_T); -+ ASSERT_PTHREAD_INTERNAL_SIZE (pthread_condattr_t, -+ struct pthread_condattr); -+ -+ memset (attr, '\0', sizeof (*attr)); -+ -+ return 0; -+} -+strong_alias (__pthread_condattr_init, pthread_condattr_init) -diff --git a/nptl_2_17/pthread_condattr_setclock_2_17.c b/nptl_2_17/pthread_condattr_setclock_2_17.c -new file mode 100644 -index 00000000..5d91f17b ---- /dev/null -+++ b/nptl_2_17/pthread_condattr_setclock_2_17.c -@@ -0,0 +1,45 @@ -+/* Copyright (C) 2003-2020 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Ulrich Drepper , 2003. -+ -+ 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 -+ . */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "pthreadP_2_17.h" -+ -+ -+int -+pthread_condattr_setclock (pthread_condattr_t *attr, clockid_t clock_id) -+{ -+ /* Only a few clocks are allowed. */ -+ if (clock_id != CLOCK_MONOTONIC && clock_id != CLOCK_REALTIME) -+ /* If more clocks are allowed some day the storing of the clock ID -+ in the pthread_cond_t structure needs to be adjusted. */ -+ return EINVAL; -+ -+ /* Make sure the value fits in the bits we reserved. */ -+ assert (clock_id < (1 << COND_NWAITERS_SHIFT)); -+ -+ int *valuep = &((struct pthread_condattr *) attr)->value; -+ -+ *valuep = ((*valuep & ~(((1 << COND_NWAITERS_SHIFT) - 1) << 1)) -+ | (clock_id << 1)); -+ -+ return 0; -+} -diff --git a/nptl_2_17/pthread_mutex_cond_lock_2_17.c b/nptl_2_17/pthread_mutex_cond_lock_2_17.c -new file mode 100644 -index 00000000..2f077130 ---- /dev/null -+++ b/nptl_2_17/pthread_mutex_cond_lock_2_17.c -@@ -0,0 +1,21 @@ -+#include -+ -+#define LLL_MUTEX_LOCK(mutex) \ -+ lll_cond_lock ((mutex)->__data.__lock, PTHREAD_MUTEX_PSHARED (mutex)) -+ -+/* Not actually elided so far. Needed? */ -+#define LLL_MUTEX_LOCK_ELISION(mutex) \ -+ ({ lll_cond_lock ((mutex)->__data.__lock, PTHREAD_MUTEX_PSHARED (mutex)); 0; }) -+ -+#define LLL_MUTEX_TRYLOCK(mutex) \ -+ lll_cond_trylock ((mutex)->__data.__lock) -+#define LLL_MUTEX_TRYLOCK_ELISION(mutex) LLL_MUTEX_TRYLOCK(mutex) -+ -+/* We need to assume that there are other threads blocked on the futex. -+ See __pthread_mutex_lock_full for further details. */ -+#define LLL_ROBUST_MUTEX_LOCK_MODIFIER FUTEX_WAITERS -+#define __pthread_mutex_lock __pthread_mutex_cond_lock -+#define __pthread_mutex_lock_full __pthread_mutex_cond_lock_full -+#define NO_INCR -+ -+#include -diff --git a/nptl_2_17/pthread_mutex_lock_2_17.c b/nptl_2_17/pthread_mutex_lock_2_17.c -new file mode 100644 -index 00000000..73ee0842 ---- /dev/null -+++ b/nptl_2_17/pthread_mutex_lock_2_17.c -@@ -0,0 +1,628 @@ -+/* Copyright (C) 2002-2020 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Ulrich Drepper , 2002. -+ -+ 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 -+ . */ -+ -+#include "pthreadP_2_17.h" -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifndef lll_lock_elision -+#define lll_lock_elision(lock, try_lock, private) ({ \ -+ lll_lock (lock, private); 0; }) -+#endif -+ -+#ifndef lll_trylock_elision -+#define lll_trylock_elision(a,t) lll_trylock(a) -+#endif -+ -+/* Some of the following definitions differ when pthread_mutex_cond_lock.c -+ includes this file. */ -+#ifndef LLL_MUTEX_LOCK -+# define LLL_MUTEX_LOCK(mutex) \ -+ lll_lock ((mutex)->__data.__lock, PTHREAD_MUTEX_PSHARED (mutex)) -+# define LLL_MUTEX_TRYLOCK(mutex) \ -+ lll_trylock ((mutex)->__data.__lock) -+# define LLL_ROBUST_MUTEX_LOCK_MODIFIER 0 -+# define LLL_MUTEX_LOCK_ELISION(mutex) \ -+ lll_lock_elision ((mutex)->__data.__lock, (mutex)->__data.__elision, \ -+ PTHREAD_MUTEX_PSHARED (mutex)) -+# define LLL_MUTEX_TRYLOCK_ELISION(mutex) \ -+ lll_trylock_elision((mutex)->__data.__lock, (mutex)->__data.__elision, \ -+ PTHREAD_MUTEX_PSHARED (mutex)) -+#endif -+ -+#ifndef FORCE_ELISION -+#define FORCE_ELISION(m, s) -+#endif -+ -+static int __pthread_mutex_lock_full (pthread_mutex_t *mutex) -+ __attribute_noinline__; -+ -+int -+__pthread_mutex_lock (pthread_mutex_t *mutex) -+{ -+ /* See concurrency notes regarding mutex type which is loaded from __kind -+ in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */ -+ unsigned int type = PTHREAD_MUTEX_TYPE_ELISION (mutex); -+ -+ LIBC_PROBE (mutex_entry, 1, mutex); -+ -+ if (__builtin_expect (type & ~(PTHREAD_MUTEX_KIND_MASK_NP -+ | PTHREAD_MUTEX_ELISION_FLAGS_NP), 0)) -+ return __pthread_mutex_lock_full (mutex); -+ -+ if (__glibc_likely (type == PTHREAD_MUTEX_TIMED_NP)) -+ { -+ FORCE_ELISION (mutex, goto elision); -+ simple: -+ /* Normal mutex. */ -+ LLL_MUTEX_LOCK (mutex); -+ assert (mutex->__data.__owner == 0); -+ } -+#ifdef HAVE_ELISION -+ else if (__glibc_likely (type == PTHREAD_MUTEX_TIMED_ELISION_NP)) -+ { -+ elision: __attribute__((unused)) -+ /* This case can never happen on a system without elision, -+ as the mutex type initialization functions will not -+ allow to set the elision flags. */ -+ /* Don't record owner or users for elision case. This is a -+ tail call. */ -+ return LLL_MUTEX_LOCK_ELISION (mutex); -+ } -+#endif -+ else if (__builtin_expect (PTHREAD_MUTEX_TYPE (mutex) -+ == PTHREAD_MUTEX_RECURSIVE_NP, 1)) -+ { -+ /* Recursive mutex. */ -+ pid_t id = THREAD_GETMEM (THREAD_SELF, tid); -+ -+ /* Check whether we already hold the mutex. */ -+ if (mutex->__data.__owner == id) -+ { -+ /* Just bump the counter. */ -+ if (__glibc_unlikely (mutex->__data.__count + 1 == 0)) -+ /* Overflow of the counter. */ -+ return EAGAIN; -+ -+ ++mutex->__data.__count; -+ -+ return 0; -+ } -+ -+ /* We have to get the mutex. */ -+ LLL_MUTEX_LOCK (mutex); -+ -+ assert (mutex->__data.__owner == 0); -+ mutex->__data.__count = 1; -+ } -+ else if (__builtin_expect (PTHREAD_MUTEX_TYPE (mutex) -+ == PTHREAD_MUTEX_ADAPTIVE_NP, 1)) -+ { -+ if (! __is_smp) -+ goto simple; -+ -+ if (LLL_MUTEX_TRYLOCK (mutex) != 0) -+ { -+ int cnt = 0; -+ int max_cnt = MIN (DEFAULT_ADAPTIVE_COUNT, -+ mutex->__data.__spins * 2 + 10); -+ do -+ { -+ if (cnt++ >= max_cnt) -+ { -+ LLL_MUTEX_LOCK (mutex); -+ break; -+ } -+ atomic_spin_nop (); -+ } -+ while (LLL_MUTEX_TRYLOCK (mutex) != 0); -+ -+ mutex->__data.__spins += (cnt - mutex->__data.__spins) / 8; -+ } -+ assert (mutex->__data.__owner == 0); -+ } -+ else -+ { -+ pid_t id = THREAD_GETMEM (THREAD_SELF, tid); -+ assert (PTHREAD_MUTEX_TYPE (mutex) == PTHREAD_MUTEX_ERRORCHECK_NP); -+ /* Check whether we already hold the mutex. */ -+ if (__glibc_unlikely (mutex->__data.__owner == id)) -+ return EDEADLK; -+ goto simple; -+ } -+ -+ pid_t id = THREAD_GETMEM (THREAD_SELF, tid); -+ -+ /* Record the ownership. */ -+ mutex->__data.__owner = id; -+#ifndef NO_INCR -+ ++mutex->__data.__nusers; -+#endif -+ -+ LIBC_PROBE (mutex_acquired, 1, mutex); -+ -+ return 0; -+} -+ -+static int -+__pthread_mutex_lock_full (pthread_mutex_t *mutex) -+{ -+ int oldval; -+ pid_t id = THREAD_GETMEM (THREAD_SELF, tid); -+ -+ switch (PTHREAD_MUTEX_TYPE (mutex)) -+ { -+ case PTHREAD_MUTEX_ROBUST_RECURSIVE_NP: -+ case PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP: -+ case PTHREAD_MUTEX_ROBUST_NORMAL_NP: -+ case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP: -+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, -+ &mutex->__data.__list.__next); -+ /* We need to set op_pending before starting the operation. Also -+ see comments at ENQUEUE_MUTEX. */ -+ __asm ("" ::: "memory"); -+ -+ oldval = mutex->__data.__lock; -+ /* This is set to FUTEX_WAITERS iff we might have shared the -+ FUTEX_WAITERS flag with other threads, and therefore need to keep it -+ set to avoid lost wake-ups. We have the same requirement in the -+ simple mutex algorithm. -+ We start with value zero for a normal mutex, and FUTEX_WAITERS if we -+ are building the special case mutexes for use from within condition -+ variables. */ -+ unsigned int assume_other_futex_waiters = LLL_ROBUST_MUTEX_LOCK_MODIFIER; -+ while (1) -+ { -+ /* Try to acquire the lock through a CAS from 0 (not acquired) to -+ our TID | assume_other_futex_waiters. */ -+ if (__glibc_likely (oldval == 0)) -+ { -+ oldval -+ = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, -+ id | assume_other_futex_waiters, 0); -+ if (__glibc_likely (oldval == 0)) -+ break; -+ } -+ -+ if ((oldval & FUTEX_OWNER_DIED) != 0) -+ { -+ /* The previous owner died. Try locking the mutex. */ -+ int newval = id; -+#ifdef NO_INCR -+ /* We are not taking assume_other_futex_waiters into accoount -+ here simply because we'll set FUTEX_WAITERS anyway. */ -+ newval |= FUTEX_WAITERS; -+#else -+ newval |= (oldval & FUTEX_WAITERS) | assume_other_futex_waiters; -+#endif -+ -+ newval -+ = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, -+ newval, oldval); -+ -+ if (newval != oldval) -+ { -+ oldval = newval; -+ continue; -+ } -+ -+ /* We got the mutex. */ -+ mutex->__data.__count = 1; -+ /* But it is inconsistent unless marked otherwise. */ -+ mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT; -+ -+ /* We must not enqueue the mutex before we have acquired it. -+ Also see comments at ENQUEUE_MUTEX. */ -+ __asm ("" ::: "memory"); -+ ENQUEUE_MUTEX (mutex); -+ /* We need to clear op_pending after we enqueue the mutex. */ -+ __asm ("" ::: "memory"); -+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); -+ -+ /* Note that we deliberately exit here. If we fall -+ through to the end of the function __nusers would be -+ incremented which is not correct because the old -+ owner has to be discounted. If we are not supposed -+ to increment __nusers we actually have to decrement -+ it here. */ -+#ifdef NO_INCR -+ --mutex->__data.__nusers; -+#endif -+ -+ return EOWNERDEAD; -+ } -+ -+ /* Check whether we already hold the mutex. */ -+ if (__glibc_unlikely ((oldval & FUTEX_TID_MASK) == id)) -+ { -+ int kind = PTHREAD_MUTEX_TYPE (mutex); -+ if (kind == PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP) -+ { -+ /* We do not need to ensure ordering wrt another memory -+ access. Also see comments at ENQUEUE_MUTEX. */ -+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, -+ NULL); -+ return EDEADLK; -+ } -+ -+ if (kind == PTHREAD_MUTEX_ROBUST_RECURSIVE_NP) -+ { -+ /* We do not need to ensure ordering wrt another memory -+ access. */ -+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, -+ NULL); -+ -+ /* Just bump the counter. */ -+ if (__glibc_unlikely (mutex->__data.__count + 1 == 0)) -+ /* Overflow of the counter. */ -+ return EAGAIN; -+ -+ ++mutex->__data.__count; -+ -+ return 0; -+ } -+ } -+ -+ /* We cannot acquire the mutex nor has its owner died. Thus, try -+ to block using futexes. Set FUTEX_WAITERS if necessary so that -+ other threads are aware that there are potentially threads -+ blocked on the futex. Restart if oldval changed in the -+ meantime. */ -+ if ((oldval & FUTEX_WAITERS) == 0) -+ { -+ if (atomic_compare_and_exchange_bool_acq (&mutex->__data.__lock, -+ oldval | FUTEX_WAITERS, -+ oldval) -+ != 0) -+ { -+ oldval = mutex->__data.__lock; -+ continue; -+ } -+ oldval |= FUTEX_WAITERS; -+ } -+ -+ /* It is now possible that we share the FUTEX_WAITERS flag with -+ another thread; therefore, update assume_other_futex_waiters so -+ that we do not forget about this when handling other cases -+ above and thus do not cause lost wake-ups. */ -+ assume_other_futex_waiters |= FUTEX_WAITERS; -+ -+ /* Block using the futex and reload current lock value. */ -+ lll_futex_wait (&mutex->__data.__lock, oldval, -+ PTHREAD_ROBUST_MUTEX_PSHARED (mutex)); -+ oldval = mutex->__data.__lock; -+ } -+ -+ /* We have acquired the mutex; check if it is still consistent. */ -+ if (__builtin_expect (mutex->__data.__owner -+ == PTHREAD_MUTEX_NOTRECOVERABLE, 0)) -+ { -+ /* This mutex is now not recoverable. */ -+ mutex->__data.__count = 0; -+ int private = PTHREAD_ROBUST_MUTEX_PSHARED (mutex); -+ lll_unlock (mutex->__data.__lock, private); -+ /* FIXME This violates the mutex destruction requirements. See -+ __pthread_mutex_unlock_full. */ -+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); -+ return ENOTRECOVERABLE; -+ } -+ -+ mutex->__data.__count = 1; -+ /* We must not enqueue the mutex before we have acquired it. -+ Also see comments at ENQUEUE_MUTEX. */ -+ __asm ("" ::: "memory"); -+ ENQUEUE_MUTEX (mutex); -+ /* We need to clear op_pending after we enqueue the mutex. */ -+ __asm ("" ::: "memory"); -+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); -+ break; -+ -+ /* The PI support requires the Linux futex system call. If that's not -+ available, pthread_mutex_init should never have allowed the type to -+ be set. So it will get the default case for an invalid type. */ -+#ifdef __NR_futex -+ case PTHREAD_MUTEX_PI_RECURSIVE_NP: -+ case PTHREAD_MUTEX_PI_ERRORCHECK_NP: -+ case PTHREAD_MUTEX_PI_NORMAL_NP: -+ case PTHREAD_MUTEX_PI_ADAPTIVE_NP: -+ case PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP: -+ case PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP: -+ case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP: -+ case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP: -+ { -+ int kind, robust; -+ { -+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s -+ in sysdeps/nptl/bits/thread-shared-types.h. */ -+ int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind)); -+ kind = mutex_kind & PTHREAD_MUTEX_KIND_MASK_NP; -+ robust = mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; -+ } -+ -+ if (robust) -+ { -+ /* Note: robust PI futexes are signaled by setting bit 0. */ -+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, -+ (void *) (((uintptr_t) &mutex->__data.__list.__next) -+ | 1)); -+ /* We need to set op_pending before starting the operation. Also -+ see comments at ENQUEUE_MUTEX. */ -+ __asm ("" ::: "memory"); -+ } -+ -+ oldval = mutex->__data.__lock; -+ -+ /* Check whether we already hold the mutex. */ -+ if (__glibc_unlikely ((oldval & FUTEX_TID_MASK) == id)) -+ { -+ if (kind == PTHREAD_MUTEX_ERRORCHECK_NP) -+ { -+ /* We do not need to ensure ordering wrt another memory -+ access. */ -+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); -+ return EDEADLK; -+ } -+ -+ if (kind == PTHREAD_MUTEX_RECURSIVE_NP) -+ { -+ /* We do not need to ensure ordering wrt another memory -+ access. */ -+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); -+ -+ /* Just bump the counter. */ -+ if (__glibc_unlikely (mutex->__data.__count + 1 == 0)) -+ /* Overflow of the counter. */ -+ return EAGAIN; -+ -+ ++mutex->__data.__count; -+ -+ return 0; -+ } -+ } -+ -+ int newval = id; -+# ifdef NO_INCR -+ newval |= FUTEX_WAITERS; -+# endif -+ oldval = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, -+ newval, 0); -+ -+ if (oldval != 0) -+ { -+ /* The mutex is locked. The kernel will now take care of -+ everything. */ -+ int private = (robust -+ ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex) -+ : PTHREAD_MUTEX_PSHARED (mutex)); -+ int e = futex_lock_pi ((unsigned int *) &mutex->__data.__lock, -+ NULL, private); -+ if (e == ESRCH || e == EDEADLK) -+ { -+ assert (e != EDEADLK -+ || (kind != PTHREAD_MUTEX_ERRORCHECK_NP -+ && kind != PTHREAD_MUTEX_RECURSIVE_NP)); -+ /* ESRCH can happen only for non-robust PI mutexes where -+ the owner of the lock died. */ -+ assert (e != ESRCH || !robust); -+ -+ /* Delay the thread indefinitely. */ -+ while (1) -+ lll_timedwait (&(int){0}, 0, 0 /* ignored */, NULL, -+ private); -+ } -+ -+ oldval = mutex->__data.__lock; -+ -+ assert (robust || (oldval & FUTEX_OWNER_DIED) == 0); -+ } -+ -+ if (__glibc_unlikely (oldval & FUTEX_OWNER_DIED)) -+ { -+ atomic_and (&mutex->__data.__lock, ~FUTEX_OWNER_DIED); -+ -+ /* We got the mutex. */ -+ mutex->__data.__count = 1; -+ /* But it is inconsistent unless marked otherwise. */ -+ mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT; -+ -+ /* We must not enqueue the mutex before we have acquired it. -+ Also see comments at ENQUEUE_MUTEX. */ -+ __asm ("" ::: "memory"); -+ ENQUEUE_MUTEX_PI (mutex); -+ /* We need to clear op_pending after we enqueue the mutex. */ -+ __asm ("" ::: "memory"); -+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); -+ -+ /* Note that we deliberately exit here. If we fall -+ through to the end of the function __nusers would be -+ incremented which is not correct because the old owner -+ has to be discounted. If we are not supposed to -+ increment __nusers we actually have to decrement it here. */ -+# ifdef NO_INCR -+ --mutex->__data.__nusers; -+# endif -+ -+ return EOWNERDEAD; -+ } -+ -+ if (robust -+ && __builtin_expect (mutex->__data.__owner -+ == PTHREAD_MUTEX_NOTRECOVERABLE, 0)) -+ { -+ /* This mutex is now not recoverable. */ -+ mutex->__data.__count = 0; -+ -+ futex_unlock_pi ((unsigned int *) &mutex->__data.__lock, -+ PTHREAD_ROBUST_MUTEX_PSHARED (mutex)); -+ -+ /* To the kernel, this will be visible after the kernel has -+ acquired the mutex in the syscall. */ -+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); -+ return ENOTRECOVERABLE; -+ } -+ -+ mutex->__data.__count = 1; -+ if (robust) -+ { -+ /* We must not enqueue the mutex before we have acquired it. -+ Also see comments at ENQUEUE_MUTEX. */ -+ __asm ("" ::: "memory"); -+ ENQUEUE_MUTEX_PI (mutex); -+ /* We need to clear op_pending after we enqueue the mutex. */ -+ __asm ("" ::: "memory"); -+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); -+ } -+ } -+ break; -+#endif /* __NR_futex. */ -+ -+ case PTHREAD_MUTEX_PP_RECURSIVE_NP: -+ case PTHREAD_MUTEX_PP_ERRORCHECK_NP: -+ case PTHREAD_MUTEX_PP_NORMAL_NP: -+ case PTHREAD_MUTEX_PP_ADAPTIVE_NP: -+ { -+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s -+ in sysdeps/nptl/bits/thread-shared-types.h. */ -+ int kind = atomic_load_relaxed (&(mutex->__data.__kind)) -+ & PTHREAD_MUTEX_KIND_MASK_NP; -+ -+ oldval = mutex->__data.__lock; -+ -+ /* Check whether we already hold the mutex. */ -+ if (mutex->__data.__owner == id) -+ { -+ if (kind == PTHREAD_MUTEX_ERRORCHECK_NP) -+ return EDEADLK; -+ -+ if (kind == PTHREAD_MUTEX_RECURSIVE_NP) -+ { -+ /* Just bump the counter. */ -+ if (__glibc_unlikely (mutex->__data.__count + 1 == 0)) -+ /* Overflow of the counter. */ -+ return EAGAIN; -+ -+ ++mutex->__data.__count; -+ -+ return 0; -+ } -+ } -+ -+ int oldprio = -1, ceilval; -+ do -+ { -+ int ceiling = (oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) -+ >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT; -+ -+ if (__pthread_current_priority () > ceiling) -+ { -+ if (oldprio != -1) -+ __pthread_tpp_change_priority (oldprio, -1); -+ return EINVAL; -+ } -+ -+ int retval = __pthread_tpp_change_priority (oldprio, ceiling); -+ if (retval) -+ return retval; -+ -+ ceilval = ceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT; -+ oldprio = ceiling; -+ -+ oldval -+ = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, -+#ifdef NO_INCR -+ ceilval | 2, -+#else -+ ceilval | 1, -+#endif -+ ceilval); -+ -+ if (oldval == ceilval) -+ break; -+ -+ do -+ { -+ oldval -+ = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, -+ ceilval | 2, -+ ceilval | 1); -+ -+ if ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval) -+ break; -+ -+ if (oldval != ceilval) -+ lll_futex_wait (&mutex->__data.__lock, ceilval | 2, -+ PTHREAD_MUTEX_PSHARED (mutex)); -+ } -+ while (atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, -+ ceilval | 2, ceilval) -+ != ceilval); -+ } -+ while ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval); -+ -+ assert (mutex->__data.__owner == 0); -+ mutex->__data.__count = 1; -+ } -+ break; -+ -+ default: -+ /* Correct code cannot set any other type. */ -+ return EINVAL; -+ } -+ -+ /* Record the ownership. */ -+ mutex->__data.__owner = id; -+#ifndef NO_INCR -+ ++mutex->__data.__nusers; -+#endif -+ -+ LIBC_PROBE (mutex_acquired, 1, mutex); -+ -+ return 0; -+} -+#ifndef __pthread_mutex_lock -+weak_alias (__pthread_mutex_lock, pthread_mutex_lock) -+hidden_def (__pthread_mutex_lock) -+#endif -+ -+ -+#ifdef NO_INCR -+void -+__pthread_mutex_cond_lock_adjust (pthread_mutex_t *mutex) -+{ -+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s -+ in sysdeps/nptl/bits/thread-shared-types.h. */ -+ int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind)); -+ assert ((mutex_kind & PTHREAD_MUTEX_PRIO_INHERIT_NP) != 0); -+ assert ((mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0); -+ assert ((mutex_kind & PTHREAD_MUTEX_PSHARED_BIT) == 0); -+ -+ /* Record the ownership. */ -+ pid_t id = THREAD_GETMEM (THREAD_SELF, tid); -+ mutex->__data.__owner = id; -+ -+ if (mutex_kind == PTHREAD_MUTEX_PI_RECURSIVE_NP) -+ ++mutex->__data.__count; -+} -+#endif -diff --git a/nptl_2_17/pthread_mutex_unlock_2_17.c b/nptl_2_17/pthread_mutex_unlock_2_17.c -new file mode 100644 -index 00000000..18ba158e ---- /dev/null -+++ b/nptl_2_17/pthread_mutex_unlock_2_17.c -@@ -0,0 +1,360 @@ -+/* Copyright (C) 2002-2020 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Ulrich Drepper , 2002. -+ -+ 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 -+ . */ -+ -+#include "pthreadP_2_17.h" -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifndef lll_unlock_elision -+#define lll_unlock_elision(a,b,c) ({ lll_unlock (a,c); 0; }) -+#endif -+ -+static int -+__pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr) -+ __attribute_noinline__; -+ -+int -+attribute_hidden -+__pthread_mutex_unlock_usercnt (pthread_mutex_t *mutex, int decr) -+{ -+ /* See concurrency notes regarding mutex type which is loaded from __kind -+ in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */ -+ int type = PTHREAD_MUTEX_TYPE_ELISION (mutex); -+ if (__builtin_expect (type -+ & ~(PTHREAD_MUTEX_KIND_MASK_NP -+ |PTHREAD_MUTEX_ELISION_FLAGS_NP), 0)) -+ return __pthread_mutex_unlock_full (mutex, decr); -+ -+ if (__builtin_expect (type, PTHREAD_MUTEX_TIMED_NP) -+ == PTHREAD_MUTEX_TIMED_NP) -+ { -+ /* Always reset the owner field. */ -+ normal: -+ mutex->__data.__owner = 0; -+ if (decr) -+ /* One less user. */ -+ --mutex->__data.__nusers; -+ -+ /* Unlock. */ -+ lll_unlock (mutex->__data.__lock, PTHREAD_MUTEX_PSHARED (mutex)); -+ -+ LIBC_PROBE (mutex_release, 1, mutex); -+ -+ return 0; -+ } -+ else if (__glibc_likely (type == PTHREAD_MUTEX_TIMED_ELISION_NP)) -+ { -+ /* Don't reset the owner/users fields for elision. */ -+ return lll_unlock_elision (mutex->__data.__lock, mutex->__data.__elision, -+ PTHREAD_MUTEX_PSHARED (mutex)); -+ } -+ else if (__builtin_expect (PTHREAD_MUTEX_TYPE (mutex) -+ == PTHREAD_MUTEX_RECURSIVE_NP, 1)) -+ { -+ /* Recursive mutex. */ -+ if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)) -+ return EPERM; -+ -+ if (--mutex->__data.__count != 0) -+ /* We still hold the mutex. */ -+ return 0; -+ goto normal; -+ } -+ else if (__builtin_expect (PTHREAD_MUTEX_TYPE (mutex) -+ == PTHREAD_MUTEX_ADAPTIVE_NP, 1)) -+ goto normal; -+ else -+ { -+ /* Error checking mutex. */ -+ assert (type == PTHREAD_MUTEX_ERRORCHECK_NP); -+ if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid) -+ || ! lll_islocked (mutex->__data.__lock)) -+ return EPERM; -+ goto normal; -+ } -+} -+ -+ -+static int -+__pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr) -+{ -+ int newowner = 0; -+ int private; -+ -+ switch (PTHREAD_MUTEX_TYPE (mutex)) -+ { -+ case PTHREAD_MUTEX_ROBUST_RECURSIVE_NP: -+ /* Recursive mutex. */ -+ if ((mutex->__data.__lock & FUTEX_TID_MASK) -+ == THREAD_GETMEM (THREAD_SELF, tid) -+ && __builtin_expect (mutex->__data.__owner -+ == PTHREAD_MUTEX_INCONSISTENT, 0)) -+ { -+ if (--mutex->__data.__count != 0) -+ /* We still hold the mutex. */ -+ return ENOTRECOVERABLE; -+ -+ goto notrecoverable; -+ } -+ -+ if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)) -+ return EPERM; -+ -+ if (--mutex->__data.__count != 0) -+ /* We still hold the mutex. */ -+ return 0; -+ -+ goto robust; -+ -+ case PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP: -+ case PTHREAD_MUTEX_ROBUST_NORMAL_NP: -+ case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP: -+ if ((mutex->__data.__lock & FUTEX_TID_MASK) -+ != THREAD_GETMEM (THREAD_SELF, tid) -+ || ! lll_islocked (mutex->__data.__lock)) -+ return EPERM; -+ -+ /* If the previous owner died and the caller did not succeed in -+ making the state consistent, mark the mutex as unrecoverable -+ and make all waiters. */ -+ if (__builtin_expect (mutex->__data.__owner -+ == PTHREAD_MUTEX_INCONSISTENT, 0)) -+ notrecoverable: -+ newowner = PTHREAD_MUTEX_NOTRECOVERABLE; -+ -+ robust: -+ /* Remove mutex from the list. */ -+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, -+ &mutex->__data.__list.__next); -+ /* We must set op_pending before we dequeue the mutex. Also see -+ comments at ENQUEUE_MUTEX. */ -+ __asm ("" ::: "memory"); -+ DEQUEUE_MUTEX (mutex); -+ -+ mutex->__data.__owner = newowner; -+ if (decr) -+ /* One less user. */ -+ --mutex->__data.__nusers; -+ -+ /* Unlock by setting the lock to 0 (not acquired); if the lock had -+ FUTEX_WAITERS set previously, then wake any waiters. -+ The unlock operation must be the last access to the mutex to not -+ violate the mutex destruction requirements (see __lll_unlock). */ -+ private = PTHREAD_ROBUST_MUTEX_PSHARED (mutex); -+ if (__glibc_unlikely ((atomic_exchange_rel (&mutex->__data.__lock, 0) -+ & FUTEX_WAITERS) != 0)) -+ lll_futex_wake (&mutex->__data.__lock, 1, private); -+ -+ /* We must clear op_pending after we release the mutex. -+ FIXME However, this violates the mutex destruction requirements -+ because another thread could acquire the mutex, destroy it, and -+ reuse the memory for something else; then, if this thread crashes, -+ and the memory happens to have a value equal to the TID, the kernel -+ will believe it is still related to the mutex (which has been -+ destroyed already) and will modify some other random object. */ -+ __asm ("" ::: "memory"); -+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); -+ break; -+ -+ /* The PI support requires the Linux futex system call. If that's not -+ available, pthread_mutex_init should never have allowed the type to -+ be set. So it will get the default case for an invalid type. */ -+#ifdef __NR_futex -+ case PTHREAD_MUTEX_PI_RECURSIVE_NP: -+ /* Recursive mutex. */ -+ if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)) -+ return EPERM; -+ -+ if (--mutex->__data.__count != 0) -+ /* We still hold the mutex. */ -+ return 0; -+ goto continue_pi_non_robust; -+ -+ case PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP: -+ /* Recursive mutex. */ -+ if ((mutex->__data.__lock & FUTEX_TID_MASK) -+ == THREAD_GETMEM (THREAD_SELF, tid) -+ && __builtin_expect (mutex->__data.__owner -+ == PTHREAD_MUTEX_INCONSISTENT, 0)) -+ { -+ if (--mutex->__data.__count != 0) -+ /* We still hold the mutex. */ -+ return ENOTRECOVERABLE; -+ -+ goto pi_notrecoverable; -+ } -+ -+ if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)) -+ return EPERM; -+ -+ if (--mutex->__data.__count != 0) -+ /* We still hold the mutex. */ -+ return 0; -+ -+ goto continue_pi_robust; -+ -+ case PTHREAD_MUTEX_PI_ERRORCHECK_NP: -+ case PTHREAD_MUTEX_PI_NORMAL_NP: -+ case PTHREAD_MUTEX_PI_ADAPTIVE_NP: -+ case PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP: -+ case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP: -+ case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP: -+ if ((mutex->__data.__lock & FUTEX_TID_MASK) -+ != THREAD_GETMEM (THREAD_SELF, tid) -+ || ! lll_islocked (mutex->__data.__lock)) -+ return EPERM; -+ -+ /* If the previous owner died and the caller did not succeed in -+ making the state consistent, mark the mutex as unrecoverable -+ and make all waiters. */ -+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s -+ in sysdeps/nptl/bits/thread-shared-types.h. */ -+ if ((atomic_load_relaxed (&(mutex->__data.__kind)) -+ & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0 -+ && __builtin_expect (mutex->__data.__owner -+ == PTHREAD_MUTEX_INCONSISTENT, 0)) -+ pi_notrecoverable: -+ newowner = PTHREAD_MUTEX_NOTRECOVERABLE; -+ -+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s -+ in sysdeps/nptl/bits/thread-shared-types.h. */ -+ if ((atomic_load_relaxed (&(mutex->__data.__kind)) -+ & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0) -+ { -+ continue_pi_robust: -+ /* Remove mutex from the list. -+ Note: robust PI futexes are signaled by setting bit 0. */ -+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, -+ (void *) (((uintptr_t) &mutex->__data.__list.__next) -+ | 1)); -+ /* We must set op_pending before we dequeue the mutex. Also see -+ comments at ENQUEUE_MUTEX. */ -+ __asm ("" ::: "memory"); -+ DEQUEUE_MUTEX (mutex); -+ } -+ -+ continue_pi_non_robust: -+ mutex->__data.__owner = newowner; -+ if (decr) -+ /* One less user. */ -+ --mutex->__data.__nusers; -+ -+ /* Unlock. Load all necessary mutex data before releasing the mutex -+ to not violate the mutex destruction requirements (see -+ lll_unlock). */ -+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s -+ in sysdeps/nptl/bits/thread-shared-types.h. */ -+ int robust = atomic_load_relaxed (&(mutex->__data.__kind)) -+ & PTHREAD_MUTEX_ROBUST_NORMAL_NP; -+ private = (robust -+ ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex) -+ : PTHREAD_MUTEX_PSHARED (mutex)); -+ /* Unlock the mutex using a CAS unless there are futex waiters or our -+ TID is not the value of __lock anymore, in which case we let the -+ kernel take care of the situation. Use release MO in the CAS to -+ synchronize with acquire MO in lock acquisitions. */ -+ int l = atomic_load_relaxed (&mutex->__data.__lock); -+ do -+ { -+ if (((l & FUTEX_WAITERS) != 0) -+ || (l != THREAD_GETMEM (THREAD_SELF, tid))) -+ { -+ futex_unlock_pi ((unsigned int *) &mutex->__data.__lock, -+ private); -+ break; -+ } -+ } -+ while (!atomic_compare_exchange_weak_release (&mutex->__data.__lock, -+ &l, 0)); -+ -+ /* This happens after the kernel releases the mutex but violates the -+ mutex destruction requirements; see comments in the code handling -+ PTHREAD_MUTEX_ROBUST_NORMAL_NP. */ -+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); -+ break; -+#endif /* __NR_futex. */ -+ -+ case PTHREAD_MUTEX_PP_RECURSIVE_NP: -+ /* Recursive mutex. */ -+ if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)) -+ return EPERM; -+ -+ if (--mutex->__data.__count != 0) -+ /* We still hold the mutex. */ -+ return 0; -+ goto pp; -+ -+ case PTHREAD_MUTEX_PP_ERRORCHECK_NP: -+ /* Error checking mutex. */ -+ if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid) -+ || (mutex->__data.__lock & ~ PTHREAD_MUTEX_PRIO_CEILING_MASK) == 0) -+ return EPERM; -+ /* FALLTHROUGH */ -+ -+ case PTHREAD_MUTEX_PP_NORMAL_NP: -+ case PTHREAD_MUTEX_PP_ADAPTIVE_NP: -+ /* Always reset the owner field. */ -+ pp: -+ mutex->__data.__owner = 0; -+ -+ if (decr) -+ /* One less user. */ -+ --mutex->__data.__nusers; -+ -+ /* Unlock. Use release MO in the CAS to synchronize with acquire MO in -+ lock acquisitions. */ -+ int newval; -+ int oldval = atomic_load_relaxed (&mutex->__data.__lock); -+ do -+ { -+ newval = oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK; -+ } -+ while (!atomic_compare_exchange_weak_release (&mutex->__data.__lock, -+ &oldval, newval)); -+ -+ if ((oldval & ~PTHREAD_MUTEX_PRIO_CEILING_MASK) > 1) -+ lll_futex_wake (&mutex->__data.__lock, 1, -+ PTHREAD_MUTEX_PSHARED (mutex)); -+ -+ int oldprio = newval >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT; -+ -+ LIBC_PROBE (mutex_release, 1, mutex); -+ -+ return __pthread_tpp_change_priority (oldprio, -1); -+ -+ default: -+ /* Correct code cannot set any other type. */ -+ return EINVAL; -+ } -+ -+ LIBC_PROBE (mutex_release, 1, mutex); -+ return 0; -+} -+ -+ -+int -+__pthread_mutex_unlock (pthread_mutex_t *mutex) -+{ -+ return __pthread_mutex_unlock_usercnt (mutex, 1); -+} -+weak_alias (__pthread_mutex_unlock, pthread_mutex_unlock) -+hidden_def (__pthread_mutex_unlock) -diff --git a/nptl_2_17/pthreadtypes_2_17.h b/nptl_2_17/pthreadtypes_2_17.h -new file mode 100644 -index 00000000..0483e44a ---- /dev/null -+++ b/nptl_2_17/pthreadtypes_2_17.h -@@ -0,0 +1,179 @@ -+/* Copyright (C) 2002-2020 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Ulrich Drepper , 2002. -+ -+ 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 -+ . */ -+ -+#ifndef _INTERNALTYPES_H -+#define _INTERNALTYPES_H 1 -+ -+#include -+#include -+#include -+ -+ -+struct pthread_attr -+{ -+ /* Scheduler parameters and priority. */ -+ struct sched_param schedparam; -+ int schedpolicy; -+ /* Various flags like detachstate, scope, etc. */ -+ int flags; -+ /* Size of guard area. */ -+ size_t guardsize; -+ /* Stack handling. */ -+ void *stackaddr; -+ size_t stacksize; -+ /* Affinity map. */ -+ cpu_set_t *cpuset; -+ size_t cpusetsize; -+}; -+ -+#define ATTR_FLAG_DETACHSTATE 0x0001 -+#define ATTR_FLAG_NOTINHERITSCHED 0x0002 -+#define ATTR_FLAG_SCOPEPROCESS 0x0004 -+#define ATTR_FLAG_STACKADDR 0x0008 -+#define ATTR_FLAG_OLDATTR 0x0010 -+#define ATTR_FLAG_SCHED_SET 0x0020 -+#define ATTR_FLAG_POLICY_SET 0x0040 -+ -+ -+/* Mutex attribute data structure. */ -+struct pthread_mutexattr -+{ -+ /* Identifier for the kind of mutex. -+ -+ Bit 31 is set if the mutex is to be shared between processes. -+ -+ Bit 0 to 30 contain one of the PTHREAD_MUTEX_ values to identify -+ the type of the mutex. */ -+ int mutexkind; -+}; -+ -+ -+/* Conditional variable attribute data structure. */ -+struct pthread_condattr -+{ -+ /* Combination of values: -+ -+ Bit 0 : flag whether conditional variable will be -+ sharable between processes. -+ Bit 1-COND_CLOCK_BITS: Clock ID. COND_CLOCK_BITS is the number of bits -+ needed to represent the ID of the clock. */ -+ int value; -+}; -+#define COND_CLOCK_BITS 1 -+#define COND_NWAITERS_SHIFT 1 -+ -+/* Read-write lock variable attribute data structure. */ -+struct pthread_rwlockattr -+{ -+ int lockkind; -+ int pshared; -+}; -+ -+ -+/* Barrier data structure. See pthread_barrier_wait for a description -+ of how these fields are used. */ -+struct pthread_barrier -+{ -+ unsigned int in; -+ unsigned int current_round; -+ unsigned int count; -+ int shared; -+ unsigned int out; -+}; -+/* See pthread_barrier_wait for a description. */ -+#define BARRIER_IN_THRESHOLD (UINT_MAX/2) -+ -+ -+/* Barrier variable attribute data structure. */ -+struct pthread_barrierattr -+{ -+ int pshared; -+}; -+ -+ -+/* Thread-local data handling. */ -+struct pthread_key_struct -+{ -+ /* Sequence numbers. Even numbers indicated vacant entries. Note -+ that zero is even. We use uintptr_t to not require padding on -+ 32- and 64-bit machines. On 64-bit machines it helps to avoid -+ wrapping, too. */ -+ uintptr_t seq; -+ -+ /* Destructor for the data. */ -+ void (*destr) (void *); -+}; -+ -+/* Check whether an entry is unused. */ -+#define KEY_UNUSED(p) (((p) & 1) == 0) -+/* Check whether a key is usable. We cannot reuse an allocated key if -+ the sequence counter would overflow after the next destroy call. -+ This would mean that we potentially free memory for a key with the -+ same sequence. This is *very* unlikely to happen, A program would -+ have to create and destroy a key 2^31 times (on 32-bit platforms, -+ on 64-bit platforms that would be 2^63). If it should happen we -+ simply don't use this specific key anymore. */ -+#define KEY_USABLE(p) (((uintptr_t) (p)) < ((uintptr_t) ((p) + 2))) -+ -+ -+/* Handling of read-write lock data. */ -+// XXX For now there is only one flag. Maybe more in future. -+#define RWLOCK_RECURSIVE(rwlock) ((rwlock)->__data.__flags != 0) -+ -+ -+/* Semaphore variable structure. */ -+struct new_sem -+{ -+#if __HAVE_64B_ATOMICS -+ /* The data field holds both value (in the least-significant 32 bits) and -+ nwaiters. */ -+# if __BYTE_ORDER == __LITTLE_ENDIAN -+# define SEM_VALUE_OFFSET 0 -+# elif __BYTE_ORDER == __BIG_ENDIAN -+# define SEM_VALUE_OFFSET 1 -+# else -+# error Unsupported byte order. -+# endif -+# define SEM_NWAITERS_SHIFT 32 -+# define SEM_VALUE_MASK (~(unsigned int)0) -+ uint64_t data; -+ int private; -+ int pad; -+#else -+# define SEM_VALUE_SHIFT 1 -+# define SEM_NWAITERS_MASK ((unsigned int)1) -+ unsigned int value; -+ int private; -+ int pad; -+ unsigned int nwaiters; -+#endif -+}; -+ -+struct old_sem -+{ -+ unsigned int value; -+}; -+ -+ -+/* Compatibility type for old conditional variable interfaces. */ -+typedef struct -+{ -+ pthread_cond_t *cond; -+} pthread_cond_2_0_t; -+ -+#endif /* internaltypes.h */ -diff --git a/nptl_2_17/tpp_2_17.c b/nptl_2_17/tpp_2_17.c -new file mode 100644 -index 00000000..56357ea3 ---- /dev/null -+++ b/nptl_2_17/tpp_2_17.c -@@ -0,0 +1,195 @@ -+/* Thread Priority Protect helpers. -+ Copyright (C) 2006-2020 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Jakub Jelinek , 2006. -+ -+ 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 -+ . */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+int __sched_fifo_min_prio = -1; -+int __sched_fifo_max_prio = -1; -+ -+/* We only want to initialize __sched_fifo_min_prio and __sched_fifo_max_prio -+ once. The standard solution would be similar to pthread_once, but then -+ readers would need to use an acquire fence. In this specific case, -+ initialization is comprised of just idempotent writes to two variables -+ that have an initial value of -1. Therefore, we can treat each variable as -+ a separate, at-least-once initialized value. This enables using just -+ relaxed MO loads and stores, but requires that consumers check for -+ initialization of each value that is to be used; see -+ __pthread_tpp_change_priority for an example. -+ */ -+void -+__init_sched_fifo_prio (void) -+{ -+ atomic_store_relaxed (&__sched_fifo_max_prio, -+ __sched_get_priority_max (SCHED_FIFO)); -+ atomic_store_relaxed (&__sched_fifo_min_prio, -+ __sched_get_priority_min (SCHED_FIFO)); -+} -+ -+int -+__pthread_tpp_change_priority (int previous_prio, int new_prio) -+{ -+ struct pthread *self = THREAD_SELF; -+ struct priority_protection_data *tpp = THREAD_GETMEM (self, tpp); -+ int fifo_min_prio = atomic_load_relaxed (&__sched_fifo_min_prio); -+ int fifo_max_prio = atomic_load_relaxed (&__sched_fifo_max_prio); -+ -+ if (tpp == NULL) -+ { -+ /* See __init_sched_fifo_prio. We need both the min and max prio, -+ so need to check both, and run initialization if either one is -+ not initialized. The memory model's write-read coherence rule -+ makes this work. */ -+ if (fifo_min_prio == -1 || fifo_max_prio == -1) -+ { -+ __init_sched_fifo_prio (); -+ fifo_min_prio = atomic_load_relaxed (&__sched_fifo_min_prio); -+ fifo_max_prio = atomic_load_relaxed (&__sched_fifo_max_prio); -+ } -+ -+ size_t size = sizeof *tpp; -+ size += (fifo_max_prio - fifo_min_prio + 1) -+ * sizeof (tpp->priomap[0]); -+ tpp = calloc (size, 1); -+ if (tpp == NULL) -+ return ENOMEM; -+ tpp->priomax = fifo_min_prio - 1; -+ THREAD_SETMEM (self, tpp, tpp); -+ } -+ -+ assert (new_prio == -1 -+ || (new_prio >= fifo_min_prio -+ && new_prio <= fifo_max_prio)); -+ assert (previous_prio == -1 -+ || (previous_prio >= fifo_min_prio -+ && previous_prio <= fifo_max_prio)); -+ -+ int priomax = tpp->priomax; -+ int newpriomax = priomax; -+ if (new_prio != -1) -+ { -+ if (tpp->priomap[new_prio - fifo_min_prio] + 1 == 0) -+ return EAGAIN; -+ ++tpp->priomap[new_prio - fifo_min_prio]; -+ if (new_prio > priomax) -+ newpriomax = new_prio; -+ } -+ -+ if (previous_prio != -1) -+ { -+ if (--tpp->priomap[previous_prio - fifo_min_prio] == 0 -+ && priomax == previous_prio -+ && previous_prio > new_prio) -+ { -+ int i; -+ for (i = previous_prio - 1; i >= fifo_min_prio; --i) -+ if (tpp->priomap[i - fifo_min_prio]) -+ break; -+ newpriomax = i; -+ } -+ } -+ -+ if (priomax == newpriomax) -+ return 0; -+ -+ /* See CREATE THREAD NOTES in nptl/pthread_create.c. */ -+ lll_lock (self->lock, LLL_PRIVATE); -+ -+ tpp->priomax = newpriomax; -+ -+ int result = 0; -+ -+ if ((self->flags & ATTR_FLAG_SCHED_SET) == 0) -+ { -+ if (__sched_getparam (self->tid, &self->schedparam) != 0) -+ result = errno; -+ else -+ self->flags |= ATTR_FLAG_SCHED_SET; -+ } -+ -+ if ((self->flags & ATTR_FLAG_POLICY_SET) == 0) -+ { -+ self->schedpolicy = __sched_getscheduler (self->tid); -+ if (self->schedpolicy == -1) -+ result = errno; -+ else -+ self->flags |= ATTR_FLAG_POLICY_SET; -+ } -+ -+ if (result == 0) -+ { -+ struct sched_param sp = self->schedparam; -+ if (sp.sched_priority < newpriomax || sp.sched_priority < priomax) -+ { -+ if (sp.sched_priority < newpriomax) -+ sp.sched_priority = newpriomax; -+ -+ if (__sched_setscheduler (self->tid, self->schedpolicy, &sp) < 0) -+ result = errno; -+ } -+ } -+ -+ lll_unlock (self->lock, LLL_PRIVATE); -+ -+ return result; -+} -+ -+int -+__pthread_current_priority (void) -+{ -+ struct pthread *self = THREAD_SELF; -+ if ((self->flags & (ATTR_FLAG_POLICY_SET | ATTR_FLAG_SCHED_SET)) -+ == (ATTR_FLAG_POLICY_SET | ATTR_FLAG_SCHED_SET)) -+ return self->schedparam.sched_priority; -+ -+ int result = 0; -+ -+ /* See CREATE THREAD NOTES in nptl/pthread_create.c. */ -+ lll_lock (self->lock, LLL_PRIVATE); -+ -+ if ((self->flags & ATTR_FLAG_SCHED_SET) == 0) -+ { -+ if (__sched_getparam (self->tid, &self->schedparam) != 0) -+ result = -1; -+ else -+ self->flags |= ATTR_FLAG_SCHED_SET; -+ } -+ -+ if ((self->flags & ATTR_FLAG_POLICY_SET) == 0) -+ { -+ self->schedpolicy = __sched_getscheduler (self->tid); -+ if (self->schedpolicy == -1) -+ result = -1; -+ else -+ self->flags |= ATTR_FLAG_POLICY_SET; -+ } -+ -+ if (result != -1) -+ result = self->schedparam.sched_priority; -+ -+ lll_unlock (self->lock, LLL_PRIVATE); -+ -+ return result; -+} -diff --git a/nptl_2_17/unwind_2_17.c b/nptl_2_17/unwind_2_17.c -new file mode 100644 -index 00000000..1534540c ---- /dev/null -+++ b/nptl_2_17/unwind_2_17.c -@@ -0,0 +1,138 @@ -+/* Copyright (C) 2003-2020 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ Contributed by Ulrich Drepper -+ and Richard Henderson , 2003. -+ -+ 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 -+ . */ -+ -+#include "pthreadP_2_17.h" -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifdef _STACK_GROWS_DOWN -+# define FRAME_LEFT(frame, other, adj) \ -+ ((uintptr_t) frame - adj >= (uintptr_t) other - adj) -+#elif _STACK_GROWS_UP -+# define FRAME_LEFT(frame, other, adj) \ -+ ((uintptr_t) frame - adj <= (uintptr_t) other - adj) -+#else -+# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP" -+#endif -+ -+static _Unwind_Reason_Code -+unwind_stop (int version, _Unwind_Action actions, -+ _Unwind_Exception_Class exc_class, -+ struct _Unwind_Exception *exc_obj, -+ struct _Unwind_Context *context, void *stop_parameter) -+{ -+ struct pthread_unwind_buf *buf = stop_parameter; -+ struct pthread *self = THREAD_SELF; -+ struct _pthread_cleanup_buffer *curp = THREAD_GETMEM (self, cleanup); -+ int do_longjump = 0; -+ -+ /* Adjust all pointers used in comparisons, so that top of thread's -+ stack is at the top of address space. Without that, things break -+ if stack is allocated above the main stack. */ -+ uintptr_t adj = (uintptr_t) self->stackblock + self->stackblock_size; -+ -+ /* Do longjmp if we're at "end of stack", aka "end of unwind data". -+ We assume there are only C frame without unwind data in between -+ here and the jmp_buf target. Otherwise simply note that the CFA -+ of a function is NOT within it's stack frame; it's the SP of the -+ previous frame. */ -+ if ((actions & _UA_END_OF_STACK) -+ || ! _JMPBUF_CFA_UNWINDS_ADJ (buf->cancel_jmp_buf[0].jmp_buf, context, -+ adj)) -+ do_longjump = 1; -+ -+ if (__glibc_unlikely (curp != NULL)) -+ { -+ /* Handle the compatibility stuff. Execute all handlers -+ registered with the old method which would be unwound by this -+ step. */ -+ struct _pthread_cleanup_buffer *oldp = buf->priv.data.cleanup; -+ void *cfa = (void *) (_Unwind_Ptr) _Unwind_GetCFA (context); -+ -+ if (curp != oldp && (do_longjump || FRAME_LEFT (cfa, curp, adj))) -+ { -+ do -+ { -+ /* Pointer to the next element. */ -+ struct _pthread_cleanup_buffer *nextp = curp->__prev; -+ -+ /* Call the handler. */ -+ curp->__routine (curp->__arg); -+ -+ /* To the next. */ -+ curp = nextp; -+ } -+ while (curp != oldp -+ && (do_longjump || FRAME_LEFT (cfa, curp, adj))); -+ -+ /* Mark the current element as handled. */ -+ THREAD_SETMEM (self, cleanup, curp); -+ } -+ } -+ -+ if (do_longjump) -+ __libc_unwind_longjmp ((struct __jmp_buf_tag *) buf->cancel_jmp_buf, 1); -+ -+ return _URC_NO_REASON; -+} -+ -+ -+static void -+unwind_cleanup (_Unwind_Reason_Code reason, struct _Unwind_Exception *exc) -+{ -+ /* When we get here a C++ catch block didn't rethrow the object. We -+ cannot handle this case and therefore abort. */ -+ __libc_fatal ("FATAL: exception not rethrown\n"); -+} -+ -+ -+void -+__cleanup_fct_attribute __attribute ((noreturn)) -+__pthread_unwind (__pthread_unwind_buf_t *buf) -+{ -+ struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf; -+ struct pthread *self = THREAD_SELF; -+ -+ /* This is not a catchable exception, so don't provide any details about -+ the exception type. We do need to initialize the field though. */ -+ THREAD_SETMEM (self, exc.exception_class, 0); -+ THREAD_SETMEM (self, exc.exception_cleanup, &unwind_cleanup); -+ -+ _Unwind_ForcedUnwind (&self->exc, unwind_stop, ibuf); -+ /* NOTREACHED */ -+ -+ /* We better do not get here. */ -+ abort (); -+} -+hidden_def (__pthread_unwind) -+ -+ -+void -+__cleanup_fct_attribute __attribute ((noreturn)) -+__pthread_unwind_next (__pthread_unwind_buf_t *buf) -+{ -+ struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf; -+ -+ __pthread_unwind ((__pthread_unwind_buf_t *) ibuf->priv.data.prev); -+} -+hidden_def (__pthread_unwind_next) -diff --git a/nptl_2_17/vars_2_17.c b/nptl_2_17/vars_2_17.c -new file mode 100644 -index 00000000..295d7e33 ---- /dev/null -+++ b/nptl_2_17/vars_2_17.c -@@ -0,0 +1,43 @@ -+/* Copyright (C) 2004-2020 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 -+ . */ -+ -+#include -+#include -+#include -+#include -+ -+/* Default thread attributes for the case when the user does not -+ provide any. */ -+struct pthread_attr __default_pthread_attr attribute_hidden; -+ -+/* Mutex protecting __default_pthread_attr. */ -+int __default_pthread_attr_lock = LLL_LOCK_INITIALIZER; -+ -+/* Flag whether the machine is SMP or not. */ -+int __is_smp attribute_hidden; -+ -+#ifndef TLS_MULTIPLE_THREADS_IN_TCB -+/* Variable set to a nonzero value either if more than one thread runs or ran, -+ or if a single-threaded process is trying to cancel itself. See -+ nptl/descr.h for more context on the single-threaded process case. */ -+int __pthread_multiple_threads attribute_hidden; -+#endif -+ -+/* Table of the key information. */ -+struct pthread_key_struct __pthread_keys[PTHREAD_KEYS_MAX] -+ __attribute__ ((nocommon)); -+hidden_data_def (__pthread_keys) --- -2.23.0 - + +diff --git a/nptl_2_17/bits/pthreadtypes_2_17.h b/nptl_2_17/bits/pthreadtypes_2_17.h +new file mode 100644 +index 00000000..da5521c1 +--- /dev/null ++++ b/nptl_2_17/bits/pthreadtypes_2_17.h +@@ -0,0 +1,127 @@ ++/* Declaration of common pthread types for all architectures. ++ Copyright (C) 2017-2018 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 ++ . */ ++ ++#ifndef _BITS_PTHREADTYPES_COMMON_H ++# define _BITS_PTHREADTYPES_COMMON_H 1 ++ ++/* For internal mutex and condition variable definitions. */ ++#include "thread-shared-types_2_17.h" ++ ++/* Thread identifiers. The structure of the attribute type is not ++ exposed on purpose. */ ++typedef unsigned long int pthread_t; ++ ++ ++/* Data structures for mutex handling. The structure of the attribute ++ type is not exposed on purpose. */ ++typedef union ++{ ++ char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; ++ int __align; ++} pthread_mutexattr_t; ++ ++ ++/* Data structure for condition variable handling. The structure of ++ the attribute type is not exposed on purpose. */ ++typedef union ++{ ++ char __size[__SIZEOF_PTHREAD_CONDATTR_T]; ++ int __align; ++} pthread_condattr_t; ++ ++ ++/* Keys for thread-specific data */ ++typedef unsigned int pthread_key_t; ++ ++ ++/* Once-only execution */ ++typedef int __ONCE_ALIGNMENT pthread_once_t; ++ ++ ++union pthread_attr_t ++{ ++ char __size[__SIZEOF_PTHREAD_ATTR_T]; ++ long int __align; ++}; ++#ifndef __have_pthread_attr_t ++typedef union pthread_attr_t pthread_attr_t; ++# define __have_pthread_attr_t 1 ++#endif ++ ++ ++typedef union ++{ ++ struct __pthread_mutex_s __data; ++ char __size[__SIZEOF_PTHREAD_MUTEX_T]; ++ long int __align; ++} pthread_mutex_t; ++ ++ ++typedef union ++{ ++struct ++{ ++ int __lock; ++ unsigned int __futex; ++ __extension__ unsigned long long int __total_seq; ++ __extension__ unsigned long long int __wakeup_seq; ++ __extension__ unsigned long long int __woken_seq; ++ void *__mutex; ++ unsigned int __nwaiters; ++ unsigned int __broadcast_seq; ++}__data; ++ char __size[__SIZEOF_PTHREAD_COND_T]; ++ long int __align; ++} pthread_cond_t; ++ ++ ++/* Data structure for reader-writer lock variable handling. The ++ structure of the attribute type is deliberately not exposed. */ ++typedef union ++{ ++ struct __pthread_rwlock_arch_t __data; ++ char __size[__SIZEOF_PTHREAD_RWLOCK_T]; ++ long int __align; ++} pthread_rwlock_t; ++ ++typedef union ++{ ++ char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; ++ long int __align; ++} pthread_rwlockattr_t; ++ ++ ++/* POSIX spinlock data type. */ ++typedef volatile int pthread_spinlock_t; ++ ++ ++/* POSIX barriers data type. The structure of the type is ++ deliberately not exposed. */ ++typedef union ++{ ++ char __size[__SIZEOF_PTHREAD_BARRIER_T]; ++ long int __align; ++} pthread_barrier_t; ++ ++typedef union ++{ ++ char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; ++ int __align; ++} pthread_barrierattr_t; ++ ++#endif +diff --git a/nptl_2_17/bits/thread-shared-types_2_17.h b/nptl_2_17/bits/thread-shared-types_2_17.h +new file mode 100644 +index 00000000..c855d0d8 +--- /dev/null ++++ b/nptl_2_17/bits/thread-shared-types_2_17.h +@@ -0,0 +1,186 @@ ++/* Common threading primitives definitions for both POSIX and C11. ++ Copyright (C) 2017-2018 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 ++ . */ ++ ++#ifndef _THREAD_SHARED_TYPES_H ++#define _THREAD_SHARED_TYPES_H 1 ++ ++#include ++/* Arch-specific definitions. Each architecture must define the following ++ macros to define the expected sizes of pthread data types: ++ ++ __SIZEOF_PTHREAD_ATTR_T - size of pthread_attr_t. ++ __SIZEOF_PTHREAD_MUTEX_T - size of pthread_mutex_t. ++ __SIZEOF_PTHREAD_MUTEXATTR_T - size of pthread_mutexattr_t. ++ __SIZEOF_PTHREAD_COND_T - size of pthread_cond_t. ++ __SIZEOF_PTHREAD_CONDATTR_T - size of pthread_condattr_t. ++ __SIZEOF_PTHREAD_RWLOCK_T - size of pthread_rwlock_t. ++ __SIZEOF_PTHREAD_RWLOCKATTR_T - size of pthread_rwlockattr_t. ++ __SIZEOF_PTHREAD_BARRIER_T - size of pthread_barrier_t. ++ __SIZEOF_PTHREAD_BARRIERATTR_T - size of pthread_barrierattr_t. ++ ++ Also, the following macros must be define for internal pthread_mutex_t ++ struct definitions (struct __pthread_mutex_s): ++ ++ __PTHREAD_COMPAT_PADDING_MID - any additional members after 'kind' ++ and before '__spin' (for 64 bits) or ++ '__nusers' (for 32 bits). ++ __PTHREAD_COMPAT_PADDING_END - any additional members at the end of ++ the internal structure. ++ __PTHREAD_MUTEX_LOCK_ELISION - 1 if the architecture supports lock ++ elision or 0 otherwise. ++ __PTHREAD_MUTEX_NUSERS_AFTER_KIND - control where to put __nusers. The ++ preferred value for new architectures ++ is 0. ++ __PTHREAD_MUTEX_USE_UNION - control whether internal __spins and ++ __list will be place inside a union for ++ linuxthreads compatibility. ++ The preferred value for new architectures ++ is 0. ++ ++ For a new port the preferred values for the required defines are: ++ ++ #define __PTHREAD_COMPAT_PADDING_MID ++ #define __PTHREAD_COMPAT_PADDING_END ++ #define __PTHREAD_MUTEX_LOCK_ELISION 0 ++ #define __PTHREAD_MUTEX_NUSERS_AFTER_KIND 0 ++ #define __PTHREAD_MUTEX_USE_UNION 0 ++ ++ __PTHREAD_MUTEX_LOCK_ELISION can be set to 1 if the hardware plans to ++ eventually support lock elision using transactional memory. ++ ++ The additional macro defines any constraint for the lock alignment ++ inside the thread structures: ++ ++ __LOCK_ALIGNMENT - for internal lock/futex usage. ++ ++ Same idea but for the once locking primitive: ++ ++ __ONCE_ALIGNMENT - for pthread_once_t/once_flag definition. ++ ++ And finally the internal pthread_rwlock_t (struct __pthread_rwlock_arch_t) ++ must be defined. ++ */ ++#include ++ ++/* Common definition of pthread_mutex_t. */ ++ ++#if !__PTHREAD_MUTEX_USE_UNION ++typedef struct __pthread_internal_list ++{ ++ struct __pthread_internal_list *__prev; ++ struct __pthread_internal_list *__next; ++} __pthread_list_t; ++#else ++typedef struct __pthread_internal_slist ++{ ++ struct __pthread_internal_slist *__next; ++} __pthread_slist_t; ++#endif ++ ++/* Lock elision support. */ ++#if __PTHREAD_MUTEX_LOCK_ELISION ++# if !__PTHREAD_MUTEX_USE_UNION ++# define __PTHREAD_SPINS_DATA \ ++ short __spins; \ ++ short __elision ++# define __PTHREAD_SPINS 0, 0 ++# else ++# define __PTHREAD_SPINS_DATA \ ++ struct \ ++ { \ ++ short __espins; \ ++ short __eelision; \ ++ } __elision_data ++# define __PTHREAD_SPINS { 0, 0 } ++# define __spins __elision_data.__espins ++# define __elision __elision_data.__eelision ++# endif ++#else ++# define __PTHREAD_SPINS_DATA int __spins ++/* Mutex __spins initializer used by PTHREAD_MUTEX_INITIALIZER. */ ++# define __PTHREAD_SPINS 0 ++#endif ++ ++struct __pthread_mutex_s ++{ ++ int __lock __LOCK_ALIGNMENT; ++ unsigned int __count; ++ int __owner; ++#if !__PTHREAD_MUTEX_NUSERS_AFTER_KIND ++ unsigned int __nusers; ++#endif ++ /* KIND must stay at this position in the structure to maintain ++ binary compatibility with static initializers. ++ ++ Concurrency notes: ++ The __kind of a mutex is initialized either by the static ++ PTHREAD_MUTEX_INITIALIZER or by a call to pthread_mutex_init. ++ ++ After a mutex has been initialized, the __kind of a mutex is usually not ++ changed. BUT it can be set to -1 in pthread_mutex_destroy or elision can ++ be enabled. This is done concurrently in the pthread_mutex_*lock functions ++ by using the macro FORCE_ELISION. This macro is only defined for ++ architectures which supports lock elision. ++ ++ For elision, there are the flags PTHREAD_MUTEX_ELISION_NP and ++ PTHREAD_MUTEX_NO_ELISION_NP which can be set in addition to the already set ++ type of a mutex. ++ Before a mutex is initialized, only PTHREAD_MUTEX_NO_ELISION_NP can be set ++ with pthread_mutexattr_settype. ++ After a mutex has been initialized, the functions pthread_mutex_*lock can ++ enable elision - if the mutex-type and the machine supports it - by setting ++ the flag PTHREAD_MUTEX_ELISION_NP. This is done concurrently. Afterwards ++ the lock / unlock functions are using specific elision code-paths. */ ++ int __kind; ++ __PTHREAD_COMPAT_PADDING_MID ++#if __PTHREAD_MUTEX_NUSERS_AFTER_KIND ++ unsigned int __nusers; ++#endif ++#if !__PTHREAD_MUTEX_USE_UNION ++ __PTHREAD_SPINS_DATA; ++ __pthread_list_t __list; ++# define __PTHREAD_MUTEX_HAVE_PREV 1 ++#else ++ __extension__ union ++ { ++ __PTHREAD_SPINS_DATA; ++ __pthread_slist_t __list; ++ }; ++# define __PTHREAD_MUTEX_HAVE_PREV 0 ++#endif ++ __PTHREAD_COMPAT_PADDING_END ++}; ++ ++ ++/* Common definition of pthread_cond_t. */ ++ ++struct __pthread_cond_s ++{ ++ int __lock; ++ unsigned int __futex; ++ __extension__ unsigned long long int __total_seq; ++ __extension__ unsigned long long int __wakeup_seq; ++ __extension__ unsigned long long int __woken_seq; ++ void *__mutex; ++ unsigned int __nwaiters; ++ unsigned int __broadcast_seq; ++ ++long int __align; ++}; ++ ++#endif /* _THREAD_SHARED_TYPES_H */ +diff --git a/nptl_2_17/internaltypes_2_17.h b/nptl_2_17/internaltypes_2_17.h +new file mode 100644 +index 00000000..603dc01c +--- /dev/null ++++ b/nptl_2_17/internaltypes_2_17.h +@@ -0,0 +1,179 @@ ++/* Copyright (C) 2002-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Ulrich Drepper , 2002. ++ ++ 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 ++ . */ ++ ++#ifndef _INTERNALTYPES_H ++#define _INTERNALTYPES_H 1 ++ ++#include ++#include ++#include ++ ++ ++struct pthread_attr ++{ ++ /* Scheduler parameters and priority. */ ++ struct sched_param schedparam; ++ int schedpolicy; ++ /* Various flags like detachstate, scope, etc. */ ++ int flags; ++ /* Size of guard area. */ ++ size_t guardsize; ++ /* Stack handling. */ ++ void *stackaddr; ++ size_t stacksize; ++ /* Affinity map. */ ++ cpu_set_t *cpuset; ++ size_t cpusetsize; ++}; ++ ++#define ATTR_FLAG_DETACHSTATE 0x0001 ++#define ATTR_FLAG_NOTINHERITSCHED 0x0002 ++#define ATTR_FLAG_SCOPEPROCESS 0x0004 ++#define ATTR_FLAG_STACKADDR 0x0008 ++#define ATTR_FLAG_OLDATTR 0x0010 ++#define ATTR_FLAG_SCHED_SET 0x0020 ++#define ATTR_FLAG_POLICY_SET 0x0040 ++ ++ ++/* Mutex attribute data structure. */ ++struct pthread_mutexattr ++{ ++ /* Identifier for the kind of mutex. ++ ++ Bit 31 is set if the mutex is to be shared between processes. ++ ++ Bit 0 to 30 contain one of the PTHREAD_MUTEX_ values to identify ++ the type of the mutex. */ ++ int mutexkind; ++}; ++ ++ ++/* Conditional variable attribute data structure. */ ++struct pthread_condattr ++{ ++ /* Combination of values: ++ ++ Bit 0 : flag whether conditional variable will be ++ sharable between processes. ++ Bit 1-COND_CLOCK_BITS: Clock ID. COND_CLOCK_BITS is the number of bits ++ needed to represent the ID of the clock. */ ++ int value; ++}; ++#define COND_CLOCK_BITS 1 ++#define COND_NWAITERS_SHIFT 1 ++ ++/* Read-write lock variable attribute data structure. */ ++struct pthread_rwlockattr ++{ ++ int lockkind; ++ int pshared; ++}; ++ ++ ++/* Barrier data structure. See pthread_barrier_wait for a description ++ of how these fields are used. */ ++struct pthread_barrier ++{ ++ unsigned int in; ++ unsigned int current_round; ++ unsigned int count; ++ int shared; ++ unsigned int out; ++}; ++/* See pthread_barrier_wait for a description. */ ++#define BARRIER_IN_THRESHOLD (UINT_MAX/2) ++ ++ ++/* Barrier variable attribute data structure. */ ++struct pthread_barrierattr ++{ ++ int pshared; ++}; ++ ++ ++/* Thread-local data handling. */ ++struct pthread_key_struct ++{ ++ /* Sequence numbers. Even numbers indicated vacant entries. Note ++ that zero is even. We use uintptr_t to not require padding on ++ 32- and 64-bit machines. On 64-bit machines it helps to avoid ++ wrapping, too. */ ++ uintptr_t seq; ++ ++ /* Destructor for the data. */ ++ void (*destr) (void *); ++}; ++ ++/* Check whether an entry is unused. */ ++#define KEY_UNUSED(p) (((p) & 1) == 0) ++/* Check whether a key is usable. We cannot reuse an allocated key if ++ the sequence counter would overflow after the next destroy call. ++ This would mean that we potentially free memory for a key with the ++ same sequence. This is *very* unlikely to happen, A program would ++ have to create and destroy a key 2^31 times (on 32-bit platforms, ++ on 64-bit platforms that would be 2^63). If it should happen we ++ simply don't use this specific key anymore. */ ++#define KEY_USABLE(p) (((uintptr_t) (p)) < ((uintptr_t) ((p) + 2))) ++ ++ ++/* Handling of read-write lock data. */ ++// XXX For now there is only one flag. Maybe more in future. ++#define RWLOCK_RECURSIVE(rwlock) ((rwlock)->__data.__flags != 0) ++ ++ ++/* Semaphore variable structure. */ ++struct new_sem ++{ ++#if __HAVE_64B_ATOMICS ++ /* The data field holds both value (in the least-significant 32 bits) and ++ nwaiters. */ ++# if __BYTE_ORDER == __LITTLE_ENDIAN ++# define SEM_VALUE_OFFSET 0 ++# elif __BYTE_ORDER == __BIG_ENDIAN ++# define SEM_VALUE_OFFSET 1 ++# else ++# error Unsupported byte order. ++# endif ++# define SEM_NWAITERS_SHIFT 32 ++# define SEM_VALUE_MASK (~(unsigned int)0) ++ uint64_t data; ++ int private; ++ int pad; ++#else ++# define SEM_VALUE_SHIFT 1 ++# define SEM_NWAITERS_MASK ((unsigned int)1) ++ unsigned int value; ++ int private; ++ int pad; ++ unsigned int nwaiters; ++#endif ++}; ++ ++struct old_sem ++{ ++ unsigned int value; ++}; ++ ++ ++/* Compatibility type for old conditional variable interfaces. */ ++typedef struct ++{ ++ pthread_cond_t *cond; ++} pthread_cond_2_0_t; ++ ++#endif /* internaltypes.h */ +diff --git a/nptl_2_17/kernel-features_2_17.h b/nptl_2_17/kernel-features_2_17.h +new file mode 100644 +index 00000000..299ae0a1 +--- /dev/null ++++ b/nptl_2_17/kernel-features_2_17.h +@@ -0,0 +1,162 @@ ++/* Set flags signalling availability of kernel features based on given ++ kernel version number. ++ Copyright (C) 1999-2018 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 ++ . */ ++ ++/* This file must not contain any C code. At least it must be protected ++ to allow using the file also in assembler files. */ ++ ++#ifndef __LINUX_KERNEL_VERSION_2_17 ++/* We assume the worst; all kernels should be supported. */ ++# define __LINUX_KERNEL_VERSION_2_17 0 ++#endif ++ ++/* We assume for __LINUX_KERNEL_VERSION the same encoding used in ++ linux/version.h. I.e., the major, minor, and subminor all get a ++ byte with the major number being in the highest byte. This means ++ we can do numeric comparisons. ++ ++ In the following we will define certain symbols depending on ++ whether the describes kernel feature is available in the kernel ++ version given by __LINUX_KERNEL_VERSION. We are not always exactly ++ recording the correct versions in which the features were ++ introduced. If somebody cares these values can afterwards be ++ corrected. */ ++ ++/* Some architectures use the socketcall multiplexer for some or all ++ socket-related operations instead of separate syscalls. ++ __ASSUME_SOCKETCALL is defined for such architectures. */ ++ ++/* The changed st_ino field appeared in 2.4.0-test6. However, SH is lame, ++ and still does not have a 64-bit inode field. */ ++#define __ASSUME_ST_INO_64_BIT 1 ++ ++/* The statfs64 syscalls are available in 2.5.74 (but not for alpha). */ ++#define __ASSUME_STATFS64 1 ++ ++/* pselect/ppoll were introduced just after 2.6.16-rc1. On x86_64 and ++ SH this appeared first in 2.6.19-rc1, on ia64 in 2.6.22-rc1. */ ++#define __ASSUME_PSELECT 1 ++ ++/* The *at syscalls were introduced just after 2.6.16-rc1. On PPC ++ they were introduced in 2.6.17-rc1, on SH in 2.6.19-rc1. */ ++#define __ASSUME_ATFCTS 1 ++ ++/* Support for inter-process robust mutexes was added in 2.6.17 (but ++ some architectures lack futex_atomic_cmpxchg_inatomic in some ++ configurations). */ ++#define __ASSUME_SET_ROBUST_LIST 1 ++ ++/* Support for various CLOEXEC and NONBLOCK flags was added in ++ 2.6.27. */ ++#define __ASSUME_IN_NONBLOCK 1 ++ ++/* Support for the FUTEX_CLOCK_REALTIME flag was added in 2.6.29. */ ++#define __ASSUME_FUTEX_CLOCK_REALTIME 1 ++ ++/* Support for preadv and pwritev was added in 2.6.30. */ ++#define __ASSUME_PREADV 1 ++#define __ASSUME_PWRITEV 1 ++ ++ ++/* Support for FUTEX_*_REQUEUE_PI was added in 2.6.31 (but some ++ * architectures lack futex_atomic_cmpxchg_inatomic in some ++ * configurations). */ ++#define __ASSUME_REQUEUE_PI 1 ++ ++/* Support for sendmmsg functionality was added in 3.0. */ ++#define __ASSUME_SENDMMSG 1 ++ ++/* On most architectures, most socket syscalls are supported for all ++ supported kernel versions, but on some socketcall architectures ++ separate syscalls were only added later. */ ++#define __ASSUME_SENDMSG_SYSCALL 1 ++#define __ASSUME_RECVMSG_SYSCALL 1 ++#define __ASSUME_ACCEPT_SYSCALL 1 ++#define __ASSUME_CONNECT_SYSCALL 1 ++#define __ASSUME_RECVFROM_SYSCALL 1 ++#define __ASSUME_SENDTO_SYSCALL 1 ++#define __ASSUME_ACCEPT4_SYSCALL 1 ++#define __ASSUME_RECVMMSG_SYSCALL 1 ++#define __ASSUME_SENDMMSG_SYSCALL 1 ++ ++/* Support for SysV IPC through wired syscalls. All supported architectures ++ either support ipc syscall and/or all the ipc correspondent syscalls. */ ++#define __ASSUME_DIRECT_SYSVIPC_SYSCALLS 1 ++ ++/* Support for p{read,write}v2 was added in 4.6. However Linux default ++ implementation does not assume the __ASSUME_* and instead use a fallback ++ implementation based on p{read,write}v and returning an error for ++ non supported flags. */ ++ ++/* Support for the renameat2 system call was added in kernel 3.15. */ ++#if __LINUX_KERNEL_VERSION >= 0x030F00 ++# define __ASSUME_RENAMEAT2 ++#endif ++ ++/* Support for the execveat syscall was added in 3.19. */ ++#if __LINUX_KERNEL_VERSION >= 0x031300 ++# define __ASSUME_EXECVEAT 1 ++#endif ++ ++#if __LINUX_KERNEL_VERSION >= 0x040400 ++# define __ASSUME_MLOCK2 1 ++#endif ++ ++#if __LINUX_KERNEL_VERSION >= 0x040500 ++# define __ASSUME_COPY_FILE_RANGE 1 ++#endif ++ ++/* Support for statx was added in kernel 4.11. */ ++#if __LINUX_KERNEL_VERSION >= 0x040B00 ++# define __ASSUME_STATX 1 ++#endif ++ ++/* Support for clone call used on fork. The signature varies across the ++ architectures with current 4 different variants: ++ ++ 1. long int clone (unsigned long flags, unsigned long newsp, ++ int *parent_tidptr, unsigned long tls, ++ int *child_tidptr) ++ ++ 2. long int clone (unsigned long newsp, unsigned long clone_flags, ++ int *parent_tidptr, int * child_tidptr, ++ unsigned long tls) ++ ++ 3. long int clone (unsigned long flags, unsigned long newsp, ++ int stack_size, int *parent_tidptr, ++ int *child_tidptr, unsigned long tls) ++ ++ 4. long int clone (unsigned long flags, unsigned long newsp, ++ int *parent_tidptr, int *child_tidptr, ++ unsigned long tls) ++ ++ The fourth variant is intended to be used as the default for newer ports, ++ Also IA64 uses the third variant but with __NR_clone2 instead of ++ __NR_clone. ++ ++ The macros names to define the variant used for the architecture is ++ similar to kernel: ++ ++ - __ASSUME_CLONE_BACKWARDS: for variant 1. ++ - __ASSUME_CLONE_BACKWARDS2: for variant 2 (s390). ++ - __ASSUME_CLONE_BACKWARDS3: for variant 3 (microblaze). ++ - __ASSUME_CLONE_DEFAULT: for variant 4. ++ - __ASSUME_CLONE2: for clone2 with variant 3 (ia64). ++ */ ++ ++#define __ASSUME_CLONE_DEFAULT 1 +diff --git a/nptl_2_17/pthreadP_2_17.h b/nptl_2_17/pthreadP_2_17.h +new file mode 100644 +index 00000000..3050fa54 +--- /dev/null ++++ b/nptl_2_17/pthreadP_2_17.h +@@ -0,0 +1,714 @@ ++/* Copyright (C) 2002-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Ulrich Drepper , 2002. ++ ++ 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 ++ . */ ++ ++#ifndef _PTHREADP_H ++#define _PTHREADP_H 1 ++ ++ ++#include ++#include "kernel-features_2_17.h" ++#include "pthread_2_17.h" ++#include "internaltypes_2_17.h" ++ ++#include ++#include ++#include ++#include "descr.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Atomic operations on TLS memory. */ ++#ifndef THREAD_ATOMIC_CMPXCHG_VAL ++# define THREAD_ATOMIC_CMPXCHG_VAL(descr, member, new, old) \ ++ atomic_compare_and_exchange_val_acq (&(descr)->member, new, old) ++#endif ++ ++#ifndef THREAD_ATOMIC_BIT_SET ++# define THREAD_ATOMIC_BIT_SET(descr, member, bit) \ ++ atomic_bit_set (&(descr)->member, bit) ++#endif ++ ++ ++/* Adaptive mutex definitions. */ ++#ifndef MAX_ADAPTIVE_COUNT ++# define MAX_ADAPTIVE_COUNT 100 ++#endif ++ ++ ++/* Magic cookie representing robust mutex with dead owner. */ ++#define PTHREAD_MUTEX_INCONSISTENT INT_MAX ++/* Magic cookie representing not recoverable robust mutex. */ ++#define PTHREAD_MUTEX_NOTRECOVERABLE (INT_MAX - 1) ++ ++ ++/* Internal mutex type value. */ ++enum ++{ ++ PTHREAD_MUTEX_KIND_MASK_NP = 3, ++ ++ PTHREAD_MUTEX_ELISION_NP = 256, ++ PTHREAD_MUTEX_NO_ELISION_NP = 512, ++ ++ PTHREAD_MUTEX_ROBUST_NORMAL_NP = 16, ++ PTHREAD_MUTEX_ROBUST_RECURSIVE_NP ++ = PTHREAD_MUTEX_ROBUST_NORMAL_NP | PTHREAD_MUTEX_RECURSIVE_NP, ++ PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP ++ = PTHREAD_MUTEX_ROBUST_NORMAL_NP | PTHREAD_MUTEX_ERRORCHECK_NP, ++ PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP ++ = PTHREAD_MUTEX_ROBUST_NORMAL_NP | PTHREAD_MUTEX_ADAPTIVE_NP, ++ PTHREAD_MUTEX_PRIO_INHERIT_NP = 32, ++ PTHREAD_MUTEX_PI_NORMAL_NP ++ = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_NORMAL, ++ PTHREAD_MUTEX_PI_RECURSIVE_NP ++ = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_RECURSIVE_NP, ++ PTHREAD_MUTEX_PI_ERRORCHECK_NP ++ = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ERRORCHECK_NP, ++ PTHREAD_MUTEX_PI_ADAPTIVE_NP ++ = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ADAPTIVE_NP, ++ PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP ++ = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_NORMAL_NP, ++ PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP ++ = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_RECURSIVE_NP, ++ PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP ++ = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP, ++ PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP ++ = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP, ++ PTHREAD_MUTEX_PRIO_PROTECT_NP = 64, ++ PTHREAD_MUTEX_PP_NORMAL_NP ++ = PTHREAD_MUTEX_PRIO_PROTECT_NP | PTHREAD_MUTEX_NORMAL, ++ PTHREAD_MUTEX_PP_RECURSIVE_NP ++ = PTHREAD_MUTEX_PRIO_PROTECT_NP | PTHREAD_MUTEX_RECURSIVE_NP, ++ PTHREAD_MUTEX_PP_ERRORCHECK_NP ++ = PTHREAD_MUTEX_PRIO_PROTECT_NP | PTHREAD_MUTEX_ERRORCHECK_NP, ++ PTHREAD_MUTEX_PP_ADAPTIVE_NP ++ = PTHREAD_MUTEX_PRIO_PROTECT_NP | PTHREAD_MUTEX_ADAPTIVE_NP, ++ PTHREAD_MUTEX_ELISION_FLAGS_NP ++ = PTHREAD_MUTEX_ELISION_NP | PTHREAD_MUTEX_NO_ELISION_NP, ++ ++ PTHREAD_MUTEX_TIMED_ELISION_NP = ++ PTHREAD_MUTEX_TIMED_NP | PTHREAD_MUTEX_ELISION_NP, ++ PTHREAD_MUTEX_TIMED_NO_ELISION_NP = ++ PTHREAD_MUTEX_TIMED_NP | PTHREAD_MUTEX_NO_ELISION_NP, ++}; ++#define PTHREAD_MUTEX_PSHARED_BIT 128 ++ ++/* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++#define PTHREAD_MUTEX_TYPE(m) \ ++ (atomic_load_relaxed (&((m)->__data.__kind)) & 127) ++/* Don't include NO_ELISION, as that type is always the same ++ as the underlying lock type. */ ++#define PTHREAD_MUTEX_TYPE_ELISION(m) \ ++ (atomic_load_relaxed (&((m)->__data.__kind)) \ ++ & (127 | PTHREAD_MUTEX_ELISION_NP)) ++ ++#if LLL_PRIVATE == 0 && LLL_SHARED == 128 ++# define PTHREAD_MUTEX_PSHARED(m) \ ++ (atomic_load_relaxed (&((m)->__data.__kind)) & 128) ++#else ++# define PTHREAD_MUTEX_PSHARED(m) \ ++ ((atomic_load_relaxed (&((m)->__data.__kind)) & 128) \ ++ ? LLL_SHARED : LLL_PRIVATE) ++#endif ++ ++/* The kernel when waking robust mutexes on exit never uses ++ FUTEX_PRIVATE_FLAG FUTEX_WAKE. */ ++#define PTHREAD_ROBUST_MUTEX_PSHARED(m) LLL_SHARED ++ ++/* Ceiling in __data.__lock. __data.__lock is signed, so don't ++ use the MSB bit in there, but in the mask also include that bit, ++ so that the compiler can optimize & PTHREAD_MUTEX_PRIO_CEILING_MASK ++ masking if the value is then shifted down by ++ PTHREAD_MUTEX_PRIO_CEILING_SHIFT. */ ++#define PTHREAD_MUTEX_PRIO_CEILING_SHIFT 19 ++#define PTHREAD_MUTEX_PRIO_CEILING_MASK 0xfff80000 ++ ++ ++/* Flags in mutex attr. */ ++#define PTHREAD_MUTEXATTR_PROTOCOL_SHIFT 28 ++#define PTHREAD_MUTEXATTR_PROTOCOL_MASK 0x30000000 ++#define PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT 12 ++#define PTHREAD_MUTEXATTR_PRIO_CEILING_MASK 0x00fff000 ++#define PTHREAD_MUTEXATTR_FLAG_ROBUST 0x40000000 ++#define PTHREAD_MUTEXATTR_FLAG_PSHARED 0x80000000 ++#define PTHREAD_MUTEXATTR_FLAG_BITS \ ++ (PTHREAD_MUTEXATTR_FLAG_ROBUST | PTHREAD_MUTEXATTR_FLAG_PSHARED \ ++ | PTHREAD_MUTEXATTR_PROTOCOL_MASK | PTHREAD_MUTEXATTR_PRIO_CEILING_MASK) ++ ++ ++/* For the following, see pthread_rwlock_common.c. */ ++#define PTHREAD_RWLOCK_WRPHASE 1 ++#define PTHREAD_RWLOCK_WRLOCKED 2 ++#define PTHREAD_RWLOCK_RWAITING 4 ++#define PTHREAD_RWLOCK_READER_SHIFT 3 ++#define PTHREAD_RWLOCK_READER_OVERFLOW ((unsigned int) 1 \ ++ << (sizeof (unsigned int) * 8 - 1)) ++#define PTHREAD_RWLOCK_WRHANDOVER ((unsigned int) 1 \ ++ << (sizeof (unsigned int) * 8 - 1)) ++#define PTHREAD_RWLOCK_FUTEX_USED 2 ++ ++ ++/* Bits used in robust mutex implementation. */ ++#define FUTEX_WAITERS 0x80000000 ++#define FUTEX_OWNER_DIED 0x40000000 ++#define FUTEX_TID_MASK 0x3fffffff ++ ++ ++/* pthread_once definitions. See __pthread_once for how these are used. */ ++#define __PTHREAD_ONCE_INPROGRESS 1 ++#define __PTHREAD_ONCE_DONE 2 ++#define __PTHREAD_ONCE_FORK_GEN_INCR 4 ++ ++/* Attribute to indicate thread creation was issued from C11 thrd_create. */ ++#define ATTR_C11_THREAD ((void*)(uintptr_t)-1) ++ ++#if 0 ++/* Condition variable definitions. See __pthread_cond_wait_common. ++ Need to be defined here so there is one place from which ++ nptl_lock_constants can grab them. */ ++#define __PTHREAD_COND_CLOCK_MONOTONIC_MASK 2 ++#define __PTHREAD_COND_SHARED_MASK 1 ++#endif ++ ++/* Internal variables. */ ++ ++ ++/* Default pthread attributes. */ ++extern struct pthread_attr __default_pthread_attr attribute_hidden; ++extern int __default_pthread_attr_lock attribute_hidden; ++ ++/* Size and alignment of static TLS block. */ ++extern size_t __static_tls_size attribute_hidden; ++extern size_t __static_tls_align_m1 attribute_hidden; ++ ++/* Flag whether the machine is SMP or not. */ ++extern int __is_smp attribute_hidden; ++ ++/* Thread descriptor handling. */ ++extern list_t __stack_user; ++hidden_proto (__stack_user) ++ ++/* Attribute handling. */ ++extern struct pthread_attr *__attr_list attribute_hidden; ++extern int __attr_list_lock attribute_hidden; ++ ++/* Concurrency handling. */ ++extern int __concurrency_level attribute_hidden; ++ ++/* Thread-local data key handling. */ ++extern struct pthread_key_struct __pthread_keys[PTHREAD_KEYS_MAX]; ++hidden_proto (__pthread_keys) ++ ++/* Number of threads running. */ ++extern unsigned int __nptl_nthreads attribute_hidden; ++ ++#ifndef __ASSUME_SET_ROBUST_LIST ++/* Negative if we do not have the system call and we can use it. */ ++extern int __set_robust_list_avail attribute_hidden; ++#endif ++ ++/* Thread Priority Protection. */ ++extern int __sched_fifo_min_prio attribute_hidden; ++extern int __sched_fifo_max_prio attribute_hidden; ++extern void __init_sched_fifo_prio (void) attribute_hidden; ++extern int __pthread_tpp_change_priority (int prev_prio, int new_prio) ++ attribute_hidden; ++extern int __pthread_current_priority (void) attribute_hidden; ++ ++/* The library can run in debugging mode where it performs a lot more ++ tests. */ ++extern int __pthread_debug attribute_hidden; ++/** For now disable debugging support. */ ++#if 0 ++# define DEBUGGING_P __builtin_expect (__pthread_debug, 0) ++# define INVALID_TD_P(pd) (DEBUGGING_P && __find_in_stack_list (pd) == NULL) ++# define INVALID_NOT_TERMINATED_TD_P(pd) INVALID_TD_P (pd) ++#else ++# define DEBUGGING_P 0 ++/* Simplified test. This will not catch all invalid descriptors but ++ is better than nothing. And if the test triggers the thread ++ descriptor is guaranteed to be invalid. */ ++# define INVALID_TD_P(pd) __builtin_expect ((pd)->tid <= 0, 0) ++# define INVALID_NOT_TERMINATED_TD_P(pd) __builtin_expect ((pd)->tid < 0, 0) ++#endif ++ ++ ++/* Cancellation test. */ ++#define CANCELLATION_P(self) \ ++ do { \ ++ int cancelhandling = THREAD_GETMEM (self, cancelhandling); \ ++ if (CANCEL_ENABLED_AND_CANCELED (cancelhandling)) \ ++ { \ ++ THREAD_SETMEM (self, result, PTHREAD_CANCELED); \ ++ __do_cancel (); \ ++ } \ ++ } while (0) ++ ++ ++extern void __pthread_unwind (__pthread_unwind_buf_t *__buf) ++ __cleanup_fct_attribute __attribute ((__noreturn__)) ++ weak_function; ++extern void __pthread_unwind_next (__pthread_unwind_buf_t *__buf) ++ __cleanup_fct_attribute __attribute ((__noreturn__)) ++ weak_function; ++extern void __pthread_register_cancel (__pthread_unwind_buf_t *__buf) ++ __cleanup_fct_attribute; ++extern void __pthread_unregister_cancel (__pthread_unwind_buf_t *__buf) ++ __cleanup_fct_attribute; ++hidden_proto (__pthread_unwind) ++hidden_proto (__pthread_unwind_next) ++hidden_proto (__pthread_register_cancel) ++hidden_proto (__pthread_unregister_cancel) ++# ifdef SHARED ++extern void attribute_hidden pthread_cancel_init (void); ++# endif ++extern void __nptl_unwind_freeres (void) attribute_hidden; ++ ++ ++/* Called when a thread reacts on a cancellation request. */ ++static inline void ++__attribute ((noreturn, always_inline)) ++__do_cancel (void) ++{ ++ struct pthread *self = THREAD_SELF; ++ ++ /* Make sure we get no more cancellations. */ ++ THREAD_ATOMIC_BIT_SET (self, cancelhandling, EXITING_BIT); ++ ++ __pthread_unwind ((__pthread_unwind_buf_t *) ++ THREAD_GETMEM (self, cleanup_jmp_buf)); ++} ++ ++ ++/* Set cancellation mode to asynchronous. */ ++#define CANCEL_ASYNC() \ ++ __pthread_enable_asynccancel () ++/* Reset to previous cancellation mode. */ ++#define CANCEL_RESET(oldtype) \ ++ __pthread_disable_asynccancel (oldtype) ++ ++# undef LIBC_CANCEL_ASYNC ++# define LIBC_CANCEL_ASYNC() CANCEL_ASYNC () ++ ++# undef LIBC_CANCEL_RESET ++# define LIBC_CANCEL_RESET(val) CANCEL_RESET (val) ++ ++# define LIBC_CANCEL_HANDLED() \ ++ __asm (".globl " __SYMBOL_PREFIX "__pthread_enable_asynccancel"); \ ++ __asm (".globl " __SYMBOL_PREFIX "__pthread_disable_asynccancel") ++ ++ ++/* Internal prototypes. */ ++ ++/* Thread list handling. */ ++extern struct pthread *__find_in_stack_list (struct pthread *pd) ++ attribute_hidden; ++ ++/* Deallocate a thread's stack after optionally making sure the thread ++ descriptor is still valid. */ ++extern void __free_tcb (struct pthread *pd) attribute_hidden; ++ ++/* Free allocated stack. */ ++extern void __deallocate_stack (struct pthread *pd) attribute_hidden; ++ ++/* Mark all the stacks except for the current one as available. This ++ function also re-initializes the lock for the stack cache. */ ++extern void __reclaim_stacks (void) attribute_hidden; ++ ++/* Make all threads's stacks executable. */ ++extern int __make_stacks_executable (void **stack_endp) attribute_hidden; ++ ++/* longjmp handling. */ ++extern void __pthread_cleanup_upto (__jmp_buf target, char *targetframe); ++hidden_proto (__pthread_cleanup_upto) ++ ++ ++/* Functions with versioned interfaces. */ ++extern int __pthread_create_2_1 (pthread_t *newthread, ++ const pthread_attr_t *attr, ++ void *(*start_routine) (void *), void *arg); ++extern int __pthread_create_2_0 (pthread_t *newthread, ++ const pthread_attr_t *attr, ++ void *(*start_routine) (void *), void *arg); ++extern int __pthread_attr_init_2_1 (pthread_attr_t *attr); ++extern int __pthread_attr_init_2_0 (pthread_attr_t *attr); ++ ++ ++/* Event handlers for libthread_db interface. */ ++extern void __nptl_create_event (void); ++extern void __nptl_death_event (void); ++hidden_proto (__nptl_create_event) ++hidden_proto (__nptl_death_event) ++ ++/* Register the generation counter in the libpthread with the libc. */ ++#ifdef TLS_MULTIPLE_THREADS_IN_TCB ++extern void __libc_pthread_init (unsigned long int *ptr, ++ void (*reclaim) (void), ++ const struct pthread_functions *functions); ++#else ++extern int *__libc_pthread_init (unsigned long int *ptr, ++ void (*reclaim) (void), ++ const struct pthread_functions *functions); ++ ++/* Variable set to a nonzero value either if more than one thread runs or ran, ++ or if a single-threaded process is trying to cancel itself. See ++ nptl/descr.h for more context on the single-threaded process case. */ ++extern int __pthread_multiple_threads attribute_hidden; ++/* Pointer to the corresponding variable in libc. */ ++extern int *__libc_multiple_threads_ptr attribute_hidden; ++#endif ++ ++/* Find a thread given its TID. */ ++extern struct pthread *__find_thread_by_id (pid_t tid) attribute_hidden ++#ifdef SHARED ++; ++#else ++weak_function; ++#define __find_thread_by_id(tid) \ ++ (__find_thread_by_id ? (__find_thread_by_id) (tid) : (struct pthread *) NULL) ++#endif ++ ++extern void __pthread_init_static_tls (struct link_map *) attribute_hidden; ++ ++extern size_t __pthread_get_minstack (const pthread_attr_t *attr); ++ ++/* Namespace save aliases. */ ++extern int __pthread_getschedparam (pthread_t thread_id, int *policy, ++ struct sched_param *param); ++extern int __pthread_setschedparam (pthread_t thread_id, int policy, ++ const struct sched_param *param); ++extern int __pthread_setcancelstate (int state, int *oldstate); ++extern int __pthread_mutex_init (pthread_mutex_t *__mutex, ++ const pthread_mutexattr_t *__mutexattr); ++extern int __pthread_mutex_destroy (pthread_mutex_t *__mutex); ++extern int __pthread_mutex_trylock (pthread_mutex_t *_mutex); ++extern int __pthread_mutex_lock (pthread_mutex_t *__mutex); ++extern int __pthread_mutex_timedlock (pthread_mutex_t *__mutex, ++ const struct timespec *__abstime); ++extern int __pthread_mutex_cond_lock (pthread_mutex_t *__mutex) ++ attribute_hidden; ++extern void __pthread_mutex_cond_lock_adjust (pthread_mutex_t *__mutex) ++ attribute_hidden; ++extern int __pthread_mutex_unlock (pthread_mutex_t *__mutex); ++extern int __pthread_mutex_unlock_usercnt (pthread_mutex_t *__mutex, ++ int __decr) attribute_hidden; ++extern int __pthread_mutexattr_init (pthread_mutexattr_t *attr); ++extern int __pthread_mutexattr_destroy (pthread_mutexattr_t *attr); ++extern int __pthread_mutexattr_settype (pthread_mutexattr_t *attr, int kind); ++extern int __pthread_attr_destroy (pthread_attr_t *attr); ++extern int __pthread_attr_getdetachstate (const pthread_attr_t *attr, ++ int *detachstate); ++extern int __pthread_attr_setdetachstate (pthread_attr_t *attr, ++ int detachstate); ++extern int __pthread_attr_getinheritsched (const pthread_attr_t *attr, ++ int *inherit); ++extern int __pthread_attr_setinheritsched (pthread_attr_t *attr, int inherit); ++extern int __pthread_attr_getschedparam (const pthread_attr_t *attr, ++ struct sched_param *param); ++extern int __pthread_attr_setschedparam (pthread_attr_t *attr, ++ const struct sched_param *param); ++extern int __pthread_attr_getschedpolicy (const pthread_attr_t *attr, ++ int *policy); ++extern int __pthread_attr_setschedpolicy (pthread_attr_t *attr, int policy); ++extern int __pthread_attr_getscope (const pthread_attr_t *attr, int *scope); ++extern int __pthread_attr_setscope (pthread_attr_t *attr, int scope); ++extern int __pthread_attr_getstackaddr (const pthread_attr_t *__restrict ++ __attr, void **__restrict __stackaddr); ++extern int __pthread_attr_setstackaddr (pthread_attr_t *__attr, ++ void *__stackaddr); ++extern int __pthread_attr_getstacksize (const pthread_attr_t *__restrict ++ __attr, ++ size_t *__restrict __stacksize); ++extern int __pthread_attr_setstacksize (pthread_attr_t *__attr, ++ size_t __stacksize); ++extern int __pthread_attr_getstack (const pthread_attr_t *__restrict __attr, ++ void **__restrict __stackaddr, ++ size_t *__restrict __stacksize); ++extern int __pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr, ++ size_t __stacksize); ++extern int __pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock, ++ const pthread_rwlockattr_t *__restrict ++ __attr); ++extern int __pthread_rwlock_destroy (pthread_rwlock_t *__rwlock); ++extern int __pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock); ++extern int __pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock); ++extern int __pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock); ++extern int __pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock); ++extern int __pthread_rwlock_unlock (pthread_rwlock_t *__rwlock); ++extern int __pthread_cond_broadcast (pthread_cond_t *cond); ++extern int __pthread_cond_destroy (pthread_cond_t *cond); ++extern int __pthread_cond_init (pthread_cond_t *cond, ++ const pthread_condattr_t *cond_attr); ++extern int __pthread_cond_signal (pthread_cond_t *cond); ++extern int __pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex); ++extern int __pthread_cond_timedwait (pthread_cond_t *cond, ++ pthread_mutex_t *mutex, ++ const struct timespec *abstime); ++extern int __pthread_cond_clockwait (pthread_cond_t *cond, ++ pthread_mutex_t *mutex, ++ clockid_t clockid, ++ const struct timespec *abstime) ++ __nonnull ((1, 2, 4)); ++extern int __pthread_condattr_destroy (pthread_condattr_t *attr); ++extern int __pthread_condattr_init (pthread_condattr_t *attr); ++extern int __pthread_key_create (pthread_key_t *key, void (*destr) (void *)); ++extern int __pthread_key_delete (pthread_key_t key); ++extern void *__pthread_getspecific (pthread_key_t key); ++extern int __pthread_setspecific (pthread_key_t key, const void *value); ++extern int __pthread_once (pthread_once_t *once_control, ++ void (*init_routine) (void)); ++extern int __pthread_atfork (void (*prepare) (void), void (*parent) (void), ++ void (*child) (void)); ++extern pthread_t __pthread_self (void); ++extern int __pthread_equal (pthread_t thread1, pthread_t thread2); ++extern int __pthread_detach (pthread_t th); ++extern int __pthread_cancel (pthread_t th); ++extern int __pthread_kill (pthread_t threadid, int signo); ++extern void __pthread_exit (void *value) __attribute__ ((__noreturn__)); ++extern int __pthread_join (pthread_t threadid, void **thread_return); ++extern int __pthread_setcanceltype (int type, int *oldtype); ++extern int __pthread_enable_asynccancel (void) attribute_hidden; ++extern void __pthread_disable_asynccancel (int oldtype) attribute_hidden; ++extern void __pthread_testcancel (void); ++extern int __pthread_timedjoin_ex (pthread_t, void **, const struct timespec *, ++ bool); ++ ++hidden_proto (__pthread_mutex_init) ++hidden_proto (__pthread_mutex_destroy) ++hidden_proto (__pthread_mutex_lock) ++hidden_proto (__pthread_mutex_trylock) ++hidden_proto (__pthread_mutex_unlock) ++hidden_proto (__pthread_rwlock_rdlock) ++hidden_proto (__pthread_rwlock_wrlock) ++hidden_proto (__pthread_rwlock_unlock) ++hidden_proto (__pthread_key_create) ++hidden_proto (__pthread_getspecific) ++hidden_proto (__pthread_setspecific) ++hidden_proto (__pthread_once) ++hidden_proto (__pthread_setcancelstate) ++hidden_proto (__pthread_testcancel) ++hidden_proto (__pthread_mutexattr_init) ++hidden_proto (__pthread_mutexattr_settype) ++hidden_proto (__pthread_timedjoin_ex) ++ ++extern int __pthread_cond_broadcast_2_0 (pthread_cond_2_0_t *cond); ++extern int __pthread_cond_destroy_2_0 (pthread_cond_2_0_t *cond); ++extern int __pthread_cond_init_2_0 (pthread_cond_2_0_t *cond, ++ const pthread_condattr_t *cond_attr); ++extern int __pthread_cond_signal_2_0 (pthread_cond_2_0_t *cond); ++extern int __pthread_cond_timedwait_2_0 (pthread_cond_2_0_t *cond, ++ pthread_mutex_t *mutex, ++ const struct timespec *abstime); ++extern int __pthread_cond_wait_2_0 (pthread_cond_2_0_t *cond, ++ pthread_mutex_t *mutex); ++ ++extern int __pthread_getaffinity_np (pthread_t th, size_t cpusetsize, ++ cpu_set_t *cpuset); ++ ++/* The two functions are in libc.so and not exported. */ ++extern int __libc_enable_asynccancel (void) attribute_hidden; ++extern void __libc_disable_asynccancel (int oldtype) attribute_hidden; ++ ++ ++/* The two functions are in librt.so and not exported. */ ++extern int __librt_enable_asynccancel (void) attribute_hidden; ++extern void __librt_disable_asynccancel (int oldtype) attribute_hidden; ++ ++/* Special versions which use non-exported functions. */ ++extern void __pthread_cleanup_push (struct _pthread_cleanup_buffer *buffer, ++ void (*routine) (void *), void *arg) ++ attribute_hidden; ++ ++/* Replace cleanup macros defined in with internal ++ versions that don't depend on unwind info and better support ++ cancellation. */ ++# undef pthread_cleanup_push ++# define pthread_cleanup_push(routine,arg) \ ++ { struct _pthread_cleanup_buffer _buffer; \ ++ __pthread_cleanup_push (&_buffer, (routine), (arg)); ++ ++extern void __pthread_cleanup_pop (struct _pthread_cleanup_buffer *buffer, ++ int execute) attribute_hidden; ++# undef pthread_cleanup_pop ++# define pthread_cleanup_pop(execute) \ ++ __pthread_cleanup_pop (&_buffer, (execute)); } ++ ++# if defined __EXCEPTIONS && !defined __cplusplus ++/* Structure to hold the cleanup handler information. */ ++struct __pthread_cleanup_combined_frame ++{ ++ void (*__cancel_routine) (void *); ++ void *__cancel_arg; ++ int __do_it; ++ struct _pthread_cleanup_buffer __buffer; ++}; ++ ++/* Special cleanup macros which register cleanup both using ++ __pthread_cleanup_{push,pop} and using cleanup attribute. This is needed ++ for pthread_once, so that it supports both throwing exceptions from the ++ pthread_once callback (only cleanup attribute works there) and cancellation ++ of the thread running the callback if the callback or some routines it ++ calls don't have unwind information. */ ++ ++static __always_inline void ++__pthread_cleanup_combined_routine (struct __pthread_cleanup_combined_frame ++ *__frame) ++{ ++ if (__frame->__do_it) ++ { ++ __frame->__cancel_routine (__frame->__cancel_arg); ++ __frame->__do_it = 0; ++ __pthread_cleanup_pop (&__frame->__buffer, 0); ++ } ++} ++ ++static inline void ++__pthread_cleanup_combined_routine_voidptr (void *__arg) ++{ ++ struct __pthread_cleanup_combined_frame *__frame ++ = (struct __pthread_cleanup_combined_frame *) __arg; ++ if (__frame->__do_it) ++ { ++ __frame->__cancel_routine (__frame->__cancel_arg); ++ __frame->__do_it = 0; ++ } ++} ++ ++# define pthread_cleanup_combined_push(routine, arg) \ ++ do { \ ++ void (*__cancel_routine) (void *) = (routine); \ ++ struct __pthread_cleanup_combined_frame __clframe \ ++ __attribute__ ((__cleanup__ (__pthread_cleanup_combined_routine))) \ ++ = { .__cancel_routine = __cancel_routine, .__cancel_arg = (arg), \ ++ .__do_it = 1 }; \ ++ __pthread_cleanup_push (&__clframe.__buffer, \ ++ __pthread_cleanup_combined_routine_voidptr, \ ++ &__clframe); ++ ++# define pthread_cleanup_combined_pop(execute) \ ++ __pthread_cleanup_pop (&__clframe.__buffer, 0); \ ++ __clframe.__do_it = 0; \ ++ if (execute) \ ++ __cancel_routine (__clframe.__cancel_arg); \ ++ } while (0) ++ ++# endif ++ ++extern void __pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *buffer, ++ void (*routine) (void *), void *arg); ++extern void __pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *buffer, ++ int execute); ++ ++/* Old cleanup interfaces, still used in libc.so. */ ++extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *buffer, ++ void (*routine) (void *), void *arg); ++extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *buffer, ++ int execute); ++extern void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *buffer, ++ void (*routine) (void *), void *arg); ++extern void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *buffer, ++ int execute); ++ ++extern void __nptl_deallocate_tsd (void) attribute_hidden; ++ ++extern void __nptl_setxid_error (struct xid_command *cmdp, int error) ++ attribute_hidden; ++extern int __nptl_setxid (struct xid_command *cmdp) attribute_hidden; ++#ifndef SHARED ++extern void __nptl_set_robust (struct pthread *self); ++#endif ++ ++extern void __nptl_stacks_freeres (void) attribute_hidden; ++extern void __shm_directory_freeres (void) attribute_hidden; ++ ++extern void __wait_lookup_done (void) attribute_hidden; ++ ++#ifdef SHARED ++# define PTHREAD_STATIC_FN_REQUIRE(name) ++#else ++# define PTHREAD_STATIC_FN_REQUIRE(name) __asm (".globl " #name); ++#endif ++ ++/* Test if the mutex is suitable for the FUTEX_WAIT_REQUEUE_PI operation. */ ++#if (defined lll_futex_wait_requeue_pi \ ++ && defined __ASSUME_REQUEUE_PI) ++# define USE_REQUEUE_PI(mut) \ ++ ((mut) && (mut) != (void *) ~0l \ ++ && (((mut)->__data.__kind \ ++ & (PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_NORMAL_NP)) \ ++ == PTHREAD_MUTEX_PRIO_INHERIT_NP)) ++#else ++# define USE_REQUEUE_PI(mut) 0 ++#endif ++ ++ ++/* Returns 0 if POL is a valid scheduling policy. */ ++static inline int ++check_sched_policy_attr (int pol) ++{ ++ if (pol == SCHED_OTHER || pol == SCHED_FIFO || pol == SCHED_RR) ++ return 0; ++ ++ return EINVAL; ++} ++ ++/* Returns 0 if PR is within the accepted range of priority values for ++ the scheduling policy POL or EINVAL otherwise. */ ++static inline int ++check_sched_priority_attr (int pr, int pol) ++{ ++ int min = __sched_get_priority_min (pol); ++ int max = __sched_get_priority_max (pol); ++ ++ if (min >= 0 && max >= 0 && pr >= min && pr <= max) ++ return 0; ++ ++ return EINVAL; ++} ++ ++/* Returns 0 if ST is a valid stack size for a thread stack and EINVAL ++ otherwise. */ ++static inline int ++check_stacksize_attr (size_t st) ++{ ++ if (st >= PTHREAD_STACK_MIN) ++ return 0; ++ ++ return EINVAL; ++} ++ ++#define ASSERT_TYPE_SIZE(type, size) \ ++ _Static_assert (sizeof (type) == size, \ ++ "sizeof (" #type ") != " #size) ++ ++#define ASSERT_PTHREAD_INTERNAL_SIZE(type, internal) \ ++ _Static_assert (sizeof ((type) { { 0 } }).__size >= sizeof (internal),\ ++ "sizeof (" #type ".__size) < sizeof (" #internal ")") ++ ++#define ASSERT_PTHREAD_STRING(x) __STRING (x) ++#define ASSERT_PTHREAD_INTERNAL_OFFSET(type, member, offset) \ ++ _Static_assert (offsetof (type, member) == offset, \ ++ "offset of " #member " field of " #type " != " \ ++ ASSERT_PTHREAD_STRING (offset)) ++ ++#endif /* pthreadP.h */ +diff --git a/nptl_2_17/pthread_2_17.h b/nptl_2_17/pthread_2_17.h +new file mode 100644 +index 00000000..3cb871a2 +--- /dev/null ++++ b/nptl_2_17/pthread_2_17.h +@@ -0,0 +1,1175 @@ ++/* Copyright (C) 2002-2018 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 ++ . */ ++ ++#ifndef _PTHREAD_H ++#define _PTHREAD_H 1 ++ ++#include "bits/pthreadtypes_2_17.h" ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++ ++/* Detach state. */ ++enum ++{ ++ PTHREAD_CREATE_JOINABLE, ++#define PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_JOINABLE ++ PTHREAD_CREATE_DETACHED ++#define PTHREAD_CREATE_DETACHED PTHREAD_CREATE_DETACHED ++}; ++ ++ ++/* Mutex types. */ ++enum ++{ ++ PTHREAD_MUTEX_TIMED_NP, ++ PTHREAD_MUTEX_RECURSIVE_NP, ++ PTHREAD_MUTEX_ERRORCHECK_NP, ++ PTHREAD_MUTEX_ADAPTIVE_NP ++#if defined __USE_UNIX98 || defined __USE_XOPEN2K8 ++ , ++ PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_TIMED_NP, ++ PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP, ++ PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP, ++ PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL ++#endif ++#ifdef __USE_GNU ++ /* For compatibility. */ ++ , PTHREAD_MUTEX_FAST_NP = PTHREAD_MUTEX_TIMED_NP ++#endif ++}; ++ ++ ++#ifdef __USE_XOPEN2K ++/* Robust mutex or not flags. */ ++enum ++{ ++ PTHREAD_MUTEX_STALLED, ++ PTHREAD_MUTEX_STALLED_NP = PTHREAD_MUTEX_STALLED, ++ PTHREAD_MUTEX_ROBUST, ++ PTHREAD_MUTEX_ROBUST_NP = PTHREAD_MUTEX_ROBUST ++}; ++#endif ++ ++ ++#if defined __USE_POSIX199506 || defined __USE_UNIX98 ++/* Mutex protocols. */ ++enum ++{ ++ PTHREAD_PRIO_NONE, ++ PTHREAD_PRIO_INHERIT, ++ PTHREAD_PRIO_PROTECT ++}; ++#endif ++ ++ ++#if __PTHREAD_MUTEX_HAVE_PREV ++# define PTHREAD_MUTEX_INITIALIZER \ ++ { { 0, 0, 0, 0, 0, __PTHREAD_SPINS, { 0, 0 } } } ++# ifdef __USE_GNU ++# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \ ++ { { 0, 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, __PTHREAD_SPINS, { 0, 0 } } } ++# define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \ ++ { { 0, 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, __PTHREAD_SPINS, { 0, 0 } } } ++# define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \ ++ { { 0, 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, __PTHREAD_SPINS, { 0, 0 } } } ++ ++# endif ++#else ++# define PTHREAD_MUTEX_INITIALIZER \ ++ { { 0, 0, 0, 0, 0, { __PTHREAD_SPINS } } } ++# ifdef __USE_GNU ++# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \ ++ { { 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, 0, { __PTHREAD_SPINS } } } ++# define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \ ++ { { 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, 0, { __PTHREAD_SPINS } } } ++# define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \ ++ { { 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, 0, { __PTHREAD_SPINS } } } ++ ++# endif ++#endif ++ ++ ++/* Read-write lock types. */ ++#if defined __USE_UNIX98 || defined __USE_XOPEN2K ++enum ++{ ++ PTHREAD_RWLOCK_PREFER_READER_NP, ++ PTHREAD_RWLOCK_PREFER_WRITER_NP, ++ PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, ++ PTHREAD_RWLOCK_DEFAULT_NP = PTHREAD_RWLOCK_PREFER_READER_NP ++}; ++ ++/* Define __PTHREAD_RWLOCK_INT_FLAGS_SHARED to 1 if pthread_rwlock_t ++ has the shared field. All 64-bit architectures have the shared field ++ in pthread_rwlock_t. */ ++#ifndef __PTHREAD_RWLOCK_INT_FLAGS_SHARED ++# if __WORDSIZE == 64 ++# define __PTHREAD_RWLOCK_INT_FLAGS_SHARED 1 ++# endif ++#endif ++ ++/* Read-write lock initializers. */ ++# define PTHREAD_RWLOCK_INITIALIZER \ ++ { { 0, 0, 0, 0, 0, 0, 0, 0, __PTHREAD_RWLOCK_ELISION_EXTRA, 0, 0 } } ++# ifdef __USE_GNU ++# ifdef __PTHREAD_RWLOCK_INT_FLAGS_SHARED ++# define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \ ++ { { 0, 0, 0, 0, 0, 0, 0, 0, __PTHREAD_RWLOCK_ELISION_EXTRA, 0, \ ++ PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP } } ++# else ++# if __BYTE_ORDER == __LITTLE_ENDIAN ++# define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \ ++ { { 0, 0, 0, 0, 0, 0, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, \ ++ 0, __PTHREAD_RWLOCK_ELISION_EXTRA, 0, 0 } } ++# else ++# define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \ ++ { { 0, 0, 0, 0, 0, 0, 0, 0, 0, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP,\ ++ 0 } } ++# endif ++# endif ++# endif ++#endif /* Unix98 or XOpen2K */ ++ ++ ++/* Scheduler inheritance. */ ++enum ++{ ++ PTHREAD_INHERIT_SCHED, ++#define PTHREAD_INHERIT_SCHED PTHREAD_INHERIT_SCHED ++ PTHREAD_EXPLICIT_SCHED ++#define PTHREAD_EXPLICIT_SCHED PTHREAD_EXPLICIT_SCHED ++}; ++ ++ ++/* Scope handling. */ ++enum ++{ ++ PTHREAD_SCOPE_SYSTEM, ++#define PTHREAD_SCOPE_SYSTEM PTHREAD_SCOPE_SYSTEM ++ PTHREAD_SCOPE_PROCESS ++#define PTHREAD_SCOPE_PROCESS PTHREAD_SCOPE_PROCESS ++}; ++ ++ ++/* Process shared or private flag. */ ++enum ++{ ++ PTHREAD_PROCESS_PRIVATE, ++#define PTHREAD_PROCESS_PRIVATE PTHREAD_PROCESS_PRIVATE ++ PTHREAD_PROCESS_SHARED ++#define PTHREAD_PROCESS_SHARED PTHREAD_PROCESS_SHARED ++}; ++ ++ ++ ++/* Conditional variable handling. */ ++#define PTHREAD_COND_INITIALIZER { { 0, 0, 0, 0, 0, (void *) 0, 0, 0 } } ++ ++/* Cleanup buffers */ ++struct _pthread_cleanup_buffer ++{ ++ void (*__routine) (void *); /* Function to call. */ ++ void *__arg; /* Its argument. */ ++ int __canceltype; /* Saved cancellation type. */ ++ struct _pthread_cleanup_buffer *__prev; /* Chaining of cleanup functions. */ ++}; ++ ++/* Cancellation */ ++enum ++{ ++ PTHREAD_CANCEL_ENABLE, ++#define PTHREAD_CANCEL_ENABLE PTHREAD_CANCEL_ENABLE ++ PTHREAD_CANCEL_DISABLE ++#define PTHREAD_CANCEL_DISABLE PTHREAD_CANCEL_DISABLE ++}; ++enum ++{ ++ PTHREAD_CANCEL_DEFERRED, ++#define PTHREAD_CANCEL_DEFERRED PTHREAD_CANCEL_DEFERRED ++ PTHREAD_CANCEL_ASYNCHRONOUS ++#define PTHREAD_CANCEL_ASYNCHRONOUS PTHREAD_CANCEL_ASYNCHRONOUS ++}; ++#define PTHREAD_CANCELED ((void *) -1) ++ ++ ++/* Single execution handling. */ ++#define PTHREAD_ONCE_INIT 0 ++ ++ ++#ifdef __USE_XOPEN2K ++/* Value returned by 'pthread_barrier_wait' for one of the threads after ++ the required number of threads have called this function. ++ -1 is distinct from 0 and all errno constants */ ++# define PTHREAD_BARRIER_SERIAL_THREAD -1 ++#endif ++ ++ ++__BEGIN_DECLS ++ ++/* Create a new thread, starting with execution of START-ROUTINE ++ getting passed ARG. Creation attributed come from ATTR. The new ++ handle is stored in *NEWTHREAD. */ ++extern int pthread_create (pthread_t *__restrict __newthread, ++ const pthread_attr_t *__restrict __attr, ++ void *(*__start_routine) (void *), ++ void *__restrict __arg) __THROWNL __nonnull ((1, 3)); ++ ++/* Terminate calling thread. ++ ++ The registered cleanup handlers are called via exception handling ++ so we cannot mark this function with __THROW.*/ ++extern void pthread_exit (void *__retval) __attribute__ ((__noreturn__)); ++ ++/* Make calling thread wait for termination of the thread TH. The ++ exit status of the thread is stored in *THREAD_RETURN, if THREAD_RETURN ++ is not NULL. ++ ++ This function is a cancellation point and therefore not marked with ++ __THROW. */ ++extern int pthread_join (pthread_t __th, void **__thread_return); ++ ++#ifdef __USE_GNU ++/* Check whether thread TH has terminated. If yes return the status of ++ the thread in *THREAD_RETURN, if THREAD_RETURN is not NULL. */ ++extern int pthread_tryjoin_np (pthread_t __th, void **__thread_return) __THROW; ++ ++/* Make calling thread wait for termination of the thread TH, but only ++ until TIMEOUT. The exit status of the thread is stored in ++ *THREAD_RETURN, if THREAD_RETURN is not NULL. ++ ++ This function is a cancellation point and therefore not marked with ++ __THROW. */ ++extern int pthread_timedjoin_np (pthread_t __th, void **__thread_return, ++ const struct timespec *__abstime); ++#endif ++ ++/* Indicate that the thread TH is never to be joined with PTHREAD_JOIN. ++ The resources of TH will therefore be freed immediately when it ++ terminates, instead of waiting for another thread to perform PTHREAD_JOIN ++ on it. */ ++extern int pthread_detach (pthread_t __th) __THROW; ++ ++ ++/* Obtain the identifier of the current thread. */ ++extern pthread_t pthread_self (void) __THROW __attribute__ ((__const__)); ++ ++/* Compare two thread identifiers. */ ++extern int pthread_equal (pthread_t __thread1, pthread_t __thread2) ++ __THROW __attribute__ ((__const__)); ++ ++ ++/* Thread attribute handling. */ ++ ++/* Initialize thread attribute *ATTR with default attributes ++ (detachstate is PTHREAD_JOINABLE, scheduling policy is SCHED_OTHER, ++ no user-provided stack). */ ++extern int pthread_attr_init (pthread_attr_t *__attr) __THROW __nonnull ((1)); ++ ++/* Destroy thread attribute *ATTR. */ ++extern int pthread_attr_destroy (pthread_attr_t *__attr) ++ __THROW __nonnull ((1)); ++ ++/* Get detach state attribute. */ ++extern int pthread_attr_getdetachstate (const pthread_attr_t *__attr, ++ int *__detachstate) ++ __THROW __nonnull ((1, 2)); ++ ++/* Set detach state attribute. */ ++extern int pthread_attr_setdetachstate (pthread_attr_t *__attr, ++ int __detachstate) ++ __THROW __nonnull ((1)); ++ ++ ++/* Get the size of the guard area created for stack overflow protection. */ ++extern int pthread_attr_getguardsize (const pthread_attr_t *__attr, ++ size_t *__guardsize) ++ __THROW __nonnull ((1, 2)); ++ ++/* Set the size of the guard area created for stack overflow protection. */ ++extern int pthread_attr_setguardsize (pthread_attr_t *__attr, ++ size_t __guardsize) ++ __THROW __nonnull ((1)); ++ ++ ++/* Return in *PARAM the scheduling parameters of *ATTR. */ ++extern int pthread_attr_getschedparam (const pthread_attr_t *__restrict __attr, ++ struct sched_param *__restrict __param) ++ __THROW __nonnull ((1, 2)); ++ ++/* Set scheduling parameters (priority, etc) in *ATTR according to PARAM. */ ++extern int pthread_attr_setschedparam (pthread_attr_t *__restrict __attr, ++ const struct sched_param *__restrict ++ __param) __THROW __nonnull ((1, 2)); ++ ++/* Return in *POLICY the scheduling policy of *ATTR. */ ++extern int pthread_attr_getschedpolicy (const pthread_attr_t *__restrict ++ __attr, int *__restrict __policy) ++ __THROW __nonnull ((1, 2)); ++ ++/* Set scheduling policy in *ATTR according to POLICY. */ ++extern int pthread_attr_setschedpolicy (pthread_attr_t *__attr, int __policy) ++ __THROW __nonnull ((1)); ++ ++/* Return in *INHERIT the scheduling inheritance mode of *ATTR. */ ++extern int pthread_attr_getinheritsched (const pthread_attr_t *__restrict ++ __attr, int *__restrict __inherit) ++ __THROW __nonnull ((1, 2)); ++ ++/* Set scheduling inheritance mode in *ATTR according to INHERIT. */ ++extern int pthread_attr_setinheritsched (pthread_attr_t *__attr, ++ int __inherit) ++ __THROW __nonnull ((1)); ++ ++ ++/* Return in *SCOPE the scheduling contention scope of *ATTR. */ ++extern int pthread_attr_getscope (const pthread_attr_t *__restrict __attr, ++ int *__restrict __scope) ++ __THROW __nonnull ((1, 2)); ++ ++/* Set scheduling contention scope in *ATTR according to SCOPE. */ ++extern int pthread_attr_setscope (pthread_attr_t *__attr, int __scope) ++ __THROW __nonnull ((1)); ++ ++/* Return the previously set address for the stack. */ ++extern int pthread_attr_getstackaddr (const pthread_attr_t *__restrict ++ __attr, void **__restrict __stackaddr) ++ __THROW __nonnull ((1, 2)) __attribute_deprecated__; ++ ++/* Set the starting address of the stack of the thread to be created. ++ Depending on whether the stack grows up or down the value must either ++ be higher or lower than all the address in the memory block. The ++ minimal size of the block must be PTHREAD_STACK_MIN. */ ++extern int pthread_attr_setstackaddr (pthread_attr_t *__attr, ++ void *__stackaddr) ++ __THROW __nonnull ((1)) __attribute_deprecated__; ++ ++/* Return the currently used minimal stack size. */ ++extern int pthread_attr_getstacksize (const pthread_attr_t *__restrict ++ __attr, size_t *__restrict __stacksize) ++ __THROW __nonnull ((1, 2)); ++ ++/* Add information about the minimum stack size needed for the thread ++ to be started. This size must never be less than PTHREAD_STACK_MIN ++ and must also not exceed the system limits. */ ++extern int pthread_attr_setstacksize (pthread_attr_t *__attr, ++ size_t __stacksize) ++ __THROW __nonnull ((1)); ++ ++#ifdef __USE_XOPEN2K ++/* Return the previously set address for the stack. */ ++extern int pthread_attr_getstack (const pthread_attr_t *__restrict __attr, ++ void **__restrict __stackaddr, ++ size_t *__restrict __stacksize) ++ __THROW __nonnull ((1, 2, 3)); ++ ++/* The following two interfaces are intended to replace the last two. They ++ require setting the address as well as the size since only setting the ++ address will make the implementation on some architectures impossible. */ ++extern int pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr, ++ size_t __stacksize) __THROW __nonnull ((1)); ++#endif ++ ++#ifdef __USE_GNU ++/* Thread created with attribute ATTR will be limited to run only on ++ the processors represented in CPUSET. */ ++extern int pthread_attr_setaffinity_np (pthread_attr_t *__attr, ++ size_t __cpusetsize, ++ const cpu_set_t *__cpuset) ++ __THROW __nonnull ((1, 3)); ++ ++/* Get bit set in CPUSET representing the processors threads created with ++ ATTR can run on. */ ++extern int pthread_attr_getaffinity_np (const pthread_attr_t *__attr, ++ size_t __cpusetsize, ++ cpu_set_t *__cpuset) ++ __THROW __nonnull ((1, 3)); ++ ++/* Get the default attributes used by pthread_create in this process. */ ++extern int pthread_getattr_default_np (pthread_attr_t *__attr) ++ __THROW __nonnull ((1)); ++ ++/* Set the default attributes to be used by pthread_create in this ++ process. */ ++extern int pthread_setattr_default_np (const pthread_attr_t *__attr) ++ __THROW __nonnull ((1)); ++ ++/* Initialize thread attribute *ATTR with attributes corresponding to the ++ already running thread TH. It shall be called on uninitialized ATTR ++ and destroyed with pthread_attr_destroy when no longer needed. */ ++extern int pthread_getattr_np (pthread_t __th, pthread_attr_t *__attr) ++ __THROW __nonnull ((2)); ++#endif ++ ++ ++/* Functions for scheduling control. */ ++ ++/* Set the scheduling parameters for TARGET_THREAD according to POLICY ++ and *PARAM. */ ++extern int pthread_setschedparam (pthread_t __target_thread, int __policy, ++ const struct sched_param *__param) ++ __THROW __nonnull ((3)); ++ ++/* Return in *POLICY and *PARAM the scheduling parameters for TARGET_THREAD. */ ++extern int pthread_getschedparam (pthread_t __target_thread, ++ int *__restrict __policy, ++ struct sched_param *__restrict __param) ++ __THROW __nonnull ((2, 3)); ++ ++/* Set the scheduling priority for TARGET_THREAD. */ ++extern int pthread_setschedprio (pthread_t __target_thread, int __prio) ++ __THROW; ++ ++ ++#ifdef __USE_GNU ++/* Get thread name visible in the kernel and its interfaces. */ ++extern int pthread_getname_np (pthread_t __target_thread, char *__buf, ++ size_t __buflen) ++ __THROW __nonnull ((2)); ++ ++/* Set thread name visible in the kernel and its interfaces. */ ++extern int pthread_setname_np (pthread_t __target_thread, const char *__name) ++ __THROW __nonnull ((2)); ++#endif ++ ++ ++#ifdef __USE_UNIX98 ++/* Determine level of concurrency. */ ++extern int pthread_getconcurrency (void) __THROW; ++ ++/* Set new concurrency level to LEVEL. */ ++extern int pthread_setconcurrency (int __level) __THROW; ++#endif ++ ++#ifdef __USE_GNU ++/* Yield the processor to another thread or process. ++ This function is similar to the POSIX `sched_yield' function but ++ might be differently implemented in the case of a m-on-n thread ++ implementation. */ ++extern int pthread_yield (void) __THROW; ++ ++ ++/* Limit specified thread TH to run only on the processors represented ++ in CPUSET. */ ++extern int pthread_setaffinity_np (pthread_t __th, size_t __cpusetsize, ++ const cpu_set_t *__cpuset) ++ __THROW __nonnull ((3)); ++ ++/* Get bit set in CPUSET representing the processors TH can run on. */ ++extern int pthread_getaffinity_np (pthread_t __th, size_t __cpusetsize, ++ cpu_set_t *__cpuset) ++ __THROW __nonnull ((3)); ++#endif ++ ++ ++/* Functions for handling initialization. */ ++ ++/* Guarantee that the initialization function INIT_ROUTINE will be called ++ only once, even if pthread_once is executed several times with the ++ same ONCE_CONTROL argument. ONCE_CONTROL must point to a static or ++ extern variable initialized to PTHREAD_ONCE_INIT. ++ ++ The initialization functions might throw exception which is why ++ this function is not marked with __THROW. */ ++extern int pthread_once (pthread_once_t *__once_control, ++ void (*__init_routine) (void)) __nonnull ((1, 2)); ++ ++ ++/* Functions for handling cancellation. ++ ++ Note that these functions are explicitly not marked to not throw an ++ exception in C++ code. If cancellation is implemented by unwinding ++ this is necessary to have the compiler generate the unwind information. */ ++ ++/* Set cancelability state of current thread to STATE, returning old ++ state in *OLDSTATE if OLDSTATE is not NULL. */ ++extern int pthread_setcancelstate (int __state, int *__oldstate); ++ ++/* Set cancellation state of current thread to TYPE, returning the old ++ type in *OLDTYPE if OLDTYPE is not NULL. */ ++extern int pthread_setcanceltype (int __type, int *__oldtype); ++ ++/* Cancel THREAD immediately or at the next possibility. */ ++extern int pthread_cancel (pthread_t __th); ++ ++/* Test for pending cancellation for the current thread and terminate ++ the thread as per pthread_exit(PTHREAD_CANCELED) if it has been ++ cancelled. */ ++extern void pthread_testcancel (void); ++ ++ ++/* Cancellation handling with integration into exception handling. */ ++ ++typedef struct ++{ ++ struct ++ { ++ __jmp_buf __cancel_jmp_buf; ++ int __mask_was_saved; ++ } __cancel_jmp_buf[1]; ++ void *__pad[4]; ++} __pthread_unwind_buf_t __attribute__ ((__aligned__)); ++ ++/* No special attributes by default. */ ++#ifndef __cleanup_fct_attribute ++# define __cleanup_fct_attribute ++#endif ++ ++ ++/* Structure to hold the cleanup handler information. */ ++struct __pthread_cleanup_frame ++{ ++ void (*__cancel_routine) (void *); ++ void *__cancel_arg; ++ int __do_it; ++ int __cancel_type; ++}; ++ ++#if defined __GNUC__ && defined __EXCEPTIONS ++# ifdef __cplusplus ++/* Class to handle cancellation handler invocation. */ ++class __pthread_cleanup_class ++{ ++ void (*__cancel_routine) (void *); ++ void *__cancel_arg; ++ int __do_it; ++ int __cancel_type; ++ ++ public: ++ __pthread_cleanup_class (void (*__fct) (void *), void *__arg) ++ : __cancel_routine (__fct), __cancel_arg (__arg), __do_it (1) { } ++ ~__pthread_cleanup_class () { if (__do_it) __cancel_routine (__cancel_arg); } ++ void __setdoit (int __newval) { __do_it = __newval; } ++ void __defer () { pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, ++ &__cancel_type); } ++ void __restore () const { pthread_setcanceltype (__cancel_type, 0); } ++}; ++ ++/* Install a cleanup handler: ROUTINE will be called with arguments ARG ++ when the thread is canceled or calls pthread_exit. ROUTINE will also ++ be called with arguments ARG when the matching pthread_cleanup_pop ++ is executed with non-zero EXECUTE argument. ++ ++ pthread_cleanup_push and pthread_cleanup_pop are macros and must always ++ be used in matching pairs at the same nesting level of braces. */ ++# define pthread_cleanup_push(routine, arg) \ ++ do { \ ++ __pthread_cleanup_class __clframe (routine, arg) ++ ++/* Remove a cleanup handler installed by the matching pthread_cleanup_push. ++ If EXECUTE is non-zero, the handler function is called. */ ++# define pthread_cleanup_pop(execute) \ ++ __clframe.__setdoit (execute); \ ++ } while (0) ++ ++# ifdef __USE_GNU ++/* Install a cleanup handler as pthread_cleanup_push does, but also ++ saves the current cancellation type and sets it to deferred ++ cancellation. */ ++# define pthread_cleanup_push_defer_np(routine, arg) \ ++ do { \ ++ __pthread_cleanup_class __clframe (routine, arg); \ ++ __clframe.__defer () ++ ++/* Remove a cleanup handler as pthread_cleanup_pop does, but also ++ restores the cancellation type that was in effect when the matching ++ pthread_cleanup_push_defer was called. */ ++# define pthread_cleanup_pop_restore_np(execute) \ ++ __clframe.__restore (); \ ++ __clframe.__setdoit (execute); \ ++ } while (0) ++# endif ++# else ++/* Function called to call the cleanup handler. As an extern inline ++ function the compiler is free to decide inlining the change when ++ needed or fall back on the copy which must exist somewhere ++ else. */ ++__extern_inline void ++__pthread_cleanup_routine (struct __pthread_cleanup_frame *__frame) ++{ ++ if (__frame->__do_it) ++ __frame->__cancel_routine (__frame->__cancel_arg); ++} ++ ++/* Install a cleanup handler: ROUTINE will be called with arguments ARG ++ when the thread is canceled or calls pthread_exit. ROUTINE will also ++ be called with arguments ARG when the matching pthread_cleanup_pop ++ is executed with non-zero EXECUTE argument. ++ ++ pthread_cleanup_push and pthread_cleanup_pop are macros and must always ++ be used in matching pairs at the same nesting level of braces. */ ++# define pthread_cleanup_push(routine, arg) \ ++ do { \ ++ struct __pthread_cleanup_frame __clframe \ ++ __attribute__ ((__cleanup__ (__pthread_cleanup_routine))) \ ++ = { .__cancel_routine = (routine), .__cancel_arg = (arg), \ ++ .__do_it = 1 }; ++ ++/* Remove a cleanup handler installed by the matching pthread_cleanup_push. ++ If EXECUTE is non-zero, the handler function is called. */ ++# define pthread_cleanup_pop(execute) \ ++ __clframe.__do_it = (execute); \ ++ } while (0) ++ ++# ifdef __USE_GNU ++/* Install a cleanup handler as pthread_cleanup_push does, but also ++ saves the current cancellation type and sets it to deferred ++ cancellation. */ ++# define pthread_cleanup_push_defer_np(routine, arg) \ ++ do { \ ++ struct __pthread_cleanup_frame __clframe \ ++ __attribute__ ((__cleanup__ (__pthread_cleanup_routine))) \ ++ = { .__cancel_routine = (routine), .__cancel_arg = (arg), \ ++ .__do_it = 1 }; \ ++ (void) pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, \ ++ &__clframe.__cancel_type) ++ ++/* Remove a cleanup handler as pthread_cleanup_pop does, but also ++ restores the cancellation type that was in effect when the matching ++ pthread_cleanup_push_defer was called. */ ++# define pthread_cleanup_pop_restore_np(execute) \ ++ (void) pthread_setcanceltype (__clframe.__cancel_type, NULL); \ ++ __clframe.__do_it = (execute); \ ++ } while (0) ++# endif ++# endif ++#else ++/* Install a cleanup handler: ROUTINE will be called with arguments ARG ++ when the thread is canceled or calls pthread_exit. ROUTINE will also ++ be called with arguments ARG when the matching pthread_cleanup_pop ++ is executed with non-zero EXECUTE argument. ++ ++ pthread_cleanup_push and pthread_cleanup_pop are macros and must always ++ be used in matching pairs at the same nesting level of braces. */ ++# define pthread_cleanup_push(routine, arg) \ ++ do { \ ++ __pthread_unwind_buf_t __cancel_buf; \ ++ void (*__cancel_routine) (void *) = (routine); \ ++ void *__cancel_arg = (arg); \ ++ int __not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) (void *) \ ++ __cancel_buf.__cancel_jmp_buf, 0); \ ++ if (__glibc_unlikely (__not_first_call)) \ ++ { \ ++ __cancel_routine (__cancel_arg); \ ++ __pthread_unwind_next (&__cancel_buf); \ ++ /* NOTREACHED */ \ ++ } \ ++ \ ++ __pthread_register_cancel (&__cancel_buf); \ ++ do { ++extern void __pthread_register_cancel (__pthread_unwind_buf_t *__buf) ++ __cleanup_fct_attribute; ++ ++/* Remove a cleanup handler installed by the matching pthread_cleanup_push. ++ If EXECUTE is non-zero, the handler function is called. */ ++# define pthread_cleanup_pop(execute) \ ++ do { } while (0);/* Empty to allow label before pthread_cleanup_pop. */\ ++ } while (0); \ ++ __pthread_unregister_cancel (&__cancel_buf); \ ++ if (execute) \ ++ __cancel_routine (__cancel_arg); \ ++ } while (0) ++extern void __pthread_unregister_cancel (__pthread_unwind_buf_t *__buf) ++ __cleanup_fct_attribute; ++ ++# ifdef __USE_GNU ++/* Install a cleanup handler as pthread_cleanup_push does, but also ++ saves the current cancellation type and sets it to deferred ++ cancellation. */ ++# define pthread_cleanup_push_defer_np(routine, arg) \ ++ do { \ ++ __pthread_unwind_buf_t __cancel_buf; \ ++ void (*__cancel_routine) (void *) = (routine); \ ++ void *__cancel_arg = (arg); \ ++ int __not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) (void *) \ ++ __cancel_buf.__cancel_jmp_buf, 0); \ ++ if (__glibc_unlikely (__not_first_call)) \ ++ { \ ++ __cancel_routine (__cancel_arg); \ ++ __pthread_unwind_next (&__cancel_buf); \ ++ /* NOTREACHED */ \ ++ } \ ++ \ ++ __pthread_register_cancel_defer (&__cancel_buf); \ ++ do { ++extern void __pthread_register_cancel_defer (__pthread_unwind_buf_t *__buf) ++ __cleanup_fct_attribute; ++ ++/* Remove a cleanup handler as pthread_cleanup_pop does, but also ++ restores the cancellation type that was in effect when the matching ++ pthread_cleanup_push_defer was called. */ ++# define pthread_cleanup_pop_restore_np(execute) \ ++ do { } while (0);/* Empty to allow label before pthread_cleanup_pop. */\ ++ } while (0); \ ++ __pthread_unregister_cancel_restore (&__cancel_buf); \ ++ if (execute) \ ++ __cancel_routine (__cancel_arg); \ ++ } while (0) ++extern void __pthread_unregister_cancel_restore (__pthread_unwind_buf_t *__buf) ++ __cleanup_fct_attribute; ++# endif ++ ++/* Internal interface to initiate cleanup. */ ++extern void __pthread_unwind_next (__pthread_unwind_buf_t *__buf) ++ __cleanup_fct_attribute __attribute__ ((__noreturn__)) ++# ifndef SHARED ++ __attribute__ ((__weak__)) ++# endif ++ ; ++#endif ++ ++/* Function used in the macros. */ ++struct __jmp_buf_tag; ++extern int __sigsetjmp (struct __jmp_buf_tag *__env, int __savemask) __THROWNL; ++ ++ ++/* Mutex handling. */ ++ ++/* Initialize a mutex. */ ++extern int pthread_mutex_init (pthread_mutex_t *__mutex, ++ const pthread_mutexattr_t *__mutexattr) ++ __THROW __nonnull ((1)); ++ ++/* Destroy a mutex. */ ++extern int pthread_mutex_destroy (pthread_mutex_t *__mutex) ++ __THROW __nonnull ((1)); ++ ++/* Try locking a mutex. */ ++extern int pthread_mutex_trylock (pthread_mutex_t *__mutex) ++ __THROWNL __nonnull ((1)); ++ ++/* Lock a mutex. */ ++extern int pthread_mutex_lock (pthread_mutex_t *__mutex) ++ __THROWNL __nonnull ((1)); ++ ++#ifdef __USE_XOPEN2K ++/* Wait until lock becomes available, or specified time passes. */ ++extern int pthread_mutex_timedlock (pthread_mutex_t *__restrict __mutex, ++ const struct timespec *__restrict ++ __abstime) __THROWNL __nonnull ((1, 2)); ++#endif ++ ++/* Unlock a mutex. */ ++extern int pthread_mutex_unlock (pthread_mutex_t *__mutex) ++ __THROWNL __nonnull ((1)); ++ ++ ++/* Get the priority ceiling of MUTEX. */ ++extern int pthread_mutex_getprioceiling (const pthread_mutex_t * ++ __restrict __mutex, ++ int *__restrict __prioceiling) ++ __THROW __nonnull ((1, 2)); ++ ++/* Set the priority ceiling of MUTEX to PRIOCEILING, return old ++ priority ceiling value in *OLD_CEILING. */ ++extern int pthread_mutex_setprioceiling (pthread_mutex_t *__restrict __mutex, ++ int __prioceiling, ++ int *__restrict __old_ceiling) ++ __THROW __nonnull ((1, 3)); ++ ++ ++#ifdef __USE_XOPEN2K8 ++/* Declare the state protected by MUTEX as consistent. */ ++extern int pthread_mutex_consistent (pthread_mutex_t *__mutex) ++ __THROW __nonnull ((1)); ++# ifdef __USE_GNU ++extern int pthread_mutex_consistent_np (pthread_mutex_t *__mutex) ++ __THROW __nonnull ((1)); ++# endif ++#endif ++ ++ ++/* Functions for handling mutex attributes. */ ++ ++/* Initialize mutex attribute object ATTR with default attributes ++ (kind is PTHREAD_MUTEX_TIMED_NP). */ ++extern int pthread_mutexattr_init (pthread_mutexattr_t *__attr) ++ __THROW __nonnull ((1)); ++ ++/* Destroy mutex attribute object ATTR. */ ++extern int pthread_mutexattr_destroy (pthread_mutexattr_t *__attr) ++ __THROW __nonnull ((1)); ++ ++/* Get the process-shared flag of the mutex attribute ATTR. */ ++extern int pthread_mutexattr_getpshared (const pthread_mutexattr_t * ++ __restrict __attr, ++ int *__restrict __pshared) ++ __THROW __nonnull ((1, 2)); ++ ++/* Set the process-shared flag of the mutex attribute ATTR. */ ++extern int pthread_mutexattr_setpshared (pthread_mutexattr_t *__attr, ++ int __pshared) ++ __THROW __nonnull ((1)); ++ ++#if defined __USE_UNIX98 || defined __USE_XOPEN2K8 ++/* Return in *KIND the mutex kind attribute in *ATTR. */ ++extern int pthread_mutexattr_gettype (const pthread_mutexattr_t *__restrict ++ __attr, int *__restrict __kind) ++ __THROW __nonnull ((1, 2)); ++ ++/* Set the mutex kind attribute in *ATTR to KIND (either PTHREAD_MUTEX_NORMAL, ++ PTHREAD_MUTEX_RECURSIVE, PTHREAD_MUTEX_ERRORCHECK, or ++ PTHREAD_MUTEX_DEFAULT). */ ++extern int pthread_mutexattr_settype (pthread_mutexattr_t *__attr, int __kind) ++ __THROW __nonnull ((1)); ++#endif ++ ++/* Return in *PROTOCOL the mutex protocol attribute in *ATTR. */ ++extern int pthread_mutexattr_getprotocol (const pthread_mutexattr_t * ++ __restrict __attr, ++ int *__restrict __protocol) ++ __THROW __nonnull ((1, 2)); ++ ++/* Set the mutex protocol attribute in *ATTR to PROTOCOL (either ++ PTHREAD_PRIO_NONE, PTHREAD_PRIO_INHERIT, or PTHREAD_PRIO_PROTECT). */ ++extern int pthread_mutexattr_setprotocol (pthread_mutexattr_t *__attr, ++ int __protocol) ++ __THROW __nonnull ((1)); ++ ++/* Return in *PRIOCEILING the mutex prioceiling attribute in *ATTR. */ ++extern int pthread_mutexattr_getprioceiling (const pthread_mutexattr_t * ++ __restrict __attr, ++ int *__restrict __prioceiling) ++ __THROW __nonnull ((1, 2)); ++ ++/* Set the mutex prioceiling attribute in *ATTR to PRIOCEILING. */ ++extern int pthread_mutexattr_setprioceiling (pthread_mutexattr_t *__attr, ++ int __prioceiling) ++ __THROW __nonnull ((1)); ++ ++#ifdef __USE_XOPEN2K ++/* Get the robustness flag of the mutex attribute ATTR. */ ++extern int pthread_mutexattr_getrobust (const pthread_mutexattr_t *__attr, ++ int *__robustness) ++ __THROW __nonnull ((1, 2)); ++# ifdef __USE_GNU ++extern int pthread_mutexattr_getrobust_np (const pthread_mutexattr_t *__attr, ++ int *__robustness) ++ __THROW __nonnull ((1, 2)); ++# endif ++ ++/* Set the robustness flag of the mutex attribute ATTR. */ ++extern int pthread_mutexattr_setrobust (pthread_mutexattr_t *__attr, ++ int __robustness) ++ __THROW __nonnull ((1)); ++# ifdef __USE_GNU ++extern int pthread_mutexattr_setrobust_np (pthread_mutexattr_t *__attr, ++ int __robustness) ++ __THROW __nonnull ((1)); ++# endif ++#endif ++ ++ ++#if defined __USE_UNIX98 || defined __USE_XOPEN2K ++/* Functions for handling read-write locks. */ ++ ++/* Initialize read-write lock RWLOCK using attributes ATTR, or use ++ the default values if later is NULL. */ ++extern int pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock, ++ const pthread_rwlockattr_t *__restrict ++ __attr) __THROW __nonnull ((1)); ++ ++/* Destroy read-write lock RWLOCK. */ ++extern int pthread_rwlock_destroy (pthread_rwlock_t *__rwlock) ++ __THROW __nonnull ((1)); ++ ++/* Acquire read lock for RWLOCK. */ ++extern int pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock) ++ __THROWNL __nonnull ((1)); ++ ++/* Try to acquire read lock for RWLOCK. */ ++extern int pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock) ++ __THROWNL __nonnull ((1)); ++ ++# ifdef __USE_XOPEN2K ++/* Try to acquire read lock for RWLOCK or return after specfied time. */ ++extern int pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock, ++ const struct timespec *__restrict ++ __abstime) __THROWNL __nonnull ((1, 2)); ++# endif ++ ++/* Acquire write lock for RWLOCK. */ ++extern int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock) ++ __THROWNL __nonnull ((1)); ++ ++/* Try to acquire write lock for RWLOCK. */ ++extern int pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock) ++ __THROWNL __nonnull ((1)); ++ ++# ifdef __USE_XOPEN2K ++/* Try to acquire write lock for RWLOCK or return after specfied time. */ ++extern int pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock, ++ const struct timespec *__restrict ++ __abstime) __THROWNL __nonnull ((1, 2)); ++# endif ++ ++/* Unlock RWLOCK. */ ++extern int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock) ++ __THROWNL __nonnull ((1)); ++ ++ ++/* Functions for handling read-write lock attributes. */ ++ ++/* Initialize attribute object ATTR with default values. */ ++extern int pthread_rwlockattr_init (pthread_rwlockattr_t *__attr) ++ __THROW __nonnull ((1)); ++ ++/* Destroy attribute object ATTR. */ ++extern int pthread_rwlockattr_destroy (pthread_rwlockattr_t *__attr) ++ __THROW __nonnull ((1)); ++ ++/* Return current setting of process-shared attribute of ATTR in PSHARED. */ ++extern int pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * ++ __restrict __attr, ++ int *__restrict __pshared) ++ __THROW __nonnull ((1, 2)); ++ ++/* Set process-shared attribute of ATTR to PSHARED. */ ++extern int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *__attr, ++ int __pshared) ++ __THROW __nonnull ((1)); ++ ++/* Return current setting of reader/writer preference. */ ++extern int pthread_rwlockattr_getkind_np (const pthread_rwlockattr_t * ++ __restrict __attr, ++ int *__restrict __pref) ++ __THROW __nonnull ((1, 2)); ++ ++/* Set reader/write preference. */ ++extern int pthread_rwlockattr_setkind_np (pthread_rwlockattr_t *__attr, ++ int __pref) __THROW __nonnull ((1)); ++#endif ++ ++ ++/* Functions for handling conditional variables. */ ++ ++/* Initialize condition variable COND using attributes ATTR, or use ++ the default values if later is NULL. */ ++extern int pthread_cond_init (pthread_cond_t *__restrict __cond, ++ const pthread_condattr_t *__restrict __cond_attr) ++ __THROW __nonnull ((1)); ++ ++/* Destroy condition variable COND. */ ++extern int pthread_cond_destroy (pthread_cond_t *__cond) ++ __THROW __nonnull ((1)); ++ ++/* Wake up one thread waiting for condition variable COND. */ ++extern int pthread_cond_signal (pthread_cond_t *__cond) ++ __THROWNL __nonnull ((1)); ++ ++/* Wake up all threads waiting for condition variables COND. */ ++extern int pthread_cond_broadcast (pthread_cond_t *__cond) ++ __THROWNL __nonnull ((1)); ++ ++/* Wait for condition variable COND to be signaled or broadcast. ++ MUTEX is assumed to be locked before. ++ ++ This function is a cancellation point and therefore not marked with ++ __THROW. */ ++extern int pthread_cond_wait (pthread_cond_t *__restrict __cond, ++ pthread_mutex_t *__restrict __mutex) ++ __nonnull ((1, 2)); ++ ++/* Wait for condition variable COND to be signaled or broadcast until ++ ABSTIME. MUTEX is assumed to be locked before. ABSTIME is an ++ absolute time specification; zero is the beginning of the epoch ++ (00:00:00 GMT, January 1, 1970). ++ ++ This function is a cancellation point and therefore not marked with ++ __THROW. */ ++extern int pthread_cond_timedwait (pthread_cond_t *__restrict __cond, ++ pthread_mutex_t *__restrict __mutex, ++ const struct timespec *__restrict __abstime) ++ __nonnull ((1, 2, 3)); ++ ++/* Wait for condition variable COND to be signaled or broadcast until ++ ABSTIME measured by the specified clock. MUTEX is assumed to be ++ locked before. CLOCK is the clock to use. ABSTIME is an absolute ++ time specification against CLOCK's epoch. ++ ++ This function is a cancellation point and therefore not marked with ++ __THROW. */ ++extern int pthread_cond_clockwait (pthread_cond_t *__restrict __cond, ++ pthread_mutex_t *__restrict __mutex, ++ __clockid_t __clock_id, ++ const struct timespec *__restrict __abstime) ++ __nonnull ((1, 2, 4)); ++ ++/* Functions for handling condition variable attributes. */ ++ ++/* Initialize condition variable attribute ATTR. */ ++extern int pthread_condattr_init (pthread_condattr_t *__attr) ++ __THROW __nonnull ((1)); ++ ++/* Destroy condition variable attribute ATTR. */ ++extern int pthread_condattr_destroy (pthread_condattr_t *__attr) ++ __THROW __nonnull ((1)); ++ ++/* Get the process-shared flag of the condition variable attribute ATTR. */ ++extern int pthread_condattr_getpshared (const pthread_condattr_t * ++ __restrict __attr, ++ int *__restrict __pshared) ++ __THROW __nonnull ((1, 2)); ++ ++/* Set the process-shared flag of the condition variable attribute ATTR. */ ++extern int pthread_condattr_setpshared (pthread_condattr_t *__attr, ++ int __pshared) __THROW __nonnull ((1)); ++ ++#ifdef __USE_XOPEN2K ++/* Get the clock selected for the condition variable attribute ATTR. */ ++extern int pthread_condattr_getclock (const pthread_condattr_t * ++ __restrict __attr, ++ __clockid_t *__restrict __clock_id) ++ __THROW __nonnull ((1, 2)); ++ ++/* Set the clock selected for the condition variable attribute ATTR. */ ++extern int pthread_condattr_setclock (pthread_condattr_t *__attr, ++ __clockid_t __clock_id) ++ __THROW __nonnull ((1)); ++#endif ++ ++ ++#ifdef __USE_XOPEN2K ++/* Functions to handle spinlocks. */ ++ ++/* Initialize the spinlock LOCK. If PSHARED is nonzero the spinlock can ++ be shared between different processes. */ ++extern int pthread_spin_init (pthread_spinlock_t *__lock, int __pshared) ++ __THROW __nonnull ((1)); ++ ++/* Destroy the spinlock LOCK. */ ++extern int pthread_spin_destroy (pthread_spinlock_t *__lock) ++ __THROW __nonnull ((1)); ++ ++/* Wait until spinlock LOCK is retrieved. */ ++extern int pthread_spin_lock (pthread_spinlock_t *__lock) ++ __THROWNL __nonnull ((1)); ++ ++/* Try to lock spinlock LOCK. */ ++extern int pthread_spin_trylock (pthread_spinlock_t *__lock) ++ __THROWNL __nonnull ((1)); ++ ++/* Release spinlock LOCK. */ ++extern int pthread_spin_unlock (pthread_spinlock_t *__lock) ++ __THROWNL __nonnull ((1)); ++ ++ ++/* Functions to handle barriers. */ ++ ++/* Initialize BARRIER with the attributes in ATTR. The barrier is ++ opened when COUNT waiters arrived. */ ++extern int pthread_barrier_init (pthread_barrier_t *__restrict __barrier, ++ const pthread_barrierattr_t *__restrict ++ __attr, unsigned int __count) ++ __THROW __nonnull ((1)); ++ ++/* Destroy a previously dynamically initialized barrier BARRIER. */ ++extern int pthread_barrier_destroy (pthread_barrier_t *__barrier) ++ __THROW __nonnull ((1)); ++ ++/* Wait on barrier BARRIER. */ ++extern int pthread_barrier_wait (pthread_barrier_t *__barrier) ++ __THROWNL __nonnull ((1)); ++ ++ ++/* Initialize barrier attribute ATTR. */ ++extern int pthread_barrierattr_init (pthread_barrierattr_t *__attr) ++ __THROW __nonnull ((1)); ++ ++/* Destroy previously dynamically initialized barrier attribute ATTR. */ ++extern int pthread_barrierattr_destroy (pthread_barrierattr_t *__attr) ++ __THROW __nonnull ((1)); ++ ++/* Get the process-shared flag of the barrier attribute ATTR. */ ++extern int pthread_barrierattr_getpshared (const pthread_barrierattr_t * ++ __restrict __attr, ++ int *__restrict __pshared) ++ __THROW __nonnull ((1, 2)); ++ ++/* Set the process-shared flag of the barrier attribute ATTR. */ ++extern int pthread_barrierattr_setpshared (pthread_barrierattr_t *__attr, ++ int __pshared) ++ __THROW __nonnull ((1)); ++#endif ++ ++ ++/* Functions for handling thread-specific data. */ ++ ++/* Create a key value identifying a location in the thread-specific ++ data area. Each thread maintains a distinct thread-specific data ++ area. DESTR_FUNCTION, if non-NULL, is called with the value ++ associated to that key when the key is destroyed. ++ DESTR_FUNCTION is not called if the value associated is NULL when ++ the key is destroyed. */ ++extern int pthread_key_create (pthread_key_t *__key, ++ void (*__destr_function) (void *)) ++ __THROW __nonnull ((1)); ++ ++/* Destroy KEY. */ ++extern int pthread_key_delete (pthread_key_t __key) __THROW; ++ ++/* Return current value of the thread-specific data slot identified by KEY. */ ++extern void *pthread_getspecific (pthread_key_t __key) __THROW; ++ ++/* Store POINTER in the thread-specific data slot identified by KEY. */ ++extern int pthread_setspecific (pthread_key_t __key, ++ const void *__pointer) __THROW ; ++ ++ ++#ifdef __USE_XOPEN2K ++/* Get ID of CPU-time clock for thread THREAD_ID. */ ++extern int pthread_getcpuclockid (pthread_t __thread_id, ++ __clockid_t *__clock_id) ++ __THROW __nonnull ((2)); ++#endif ++ ++ ++/* Install handlers to be called when a new process is created with FORK. ++ The PREPARE handler is called in the parent process just before performing ++ FORK. The PARENT handler is called in the parent process just after FORK. ++ The CHILD handler is called in the child process. Each of the three ++ handlers can be NULL, meaning that no handler needs to be called at that ++ point. ++ PTHREAD_ATFORK can be called several times, in which case the PREPARE ++ handlers are called in LIFO order (last added with PTHREAD_ATFORK, ++ first called before FORK), and the PARENT and CHILD handlers are called ++ in FIFO (first added, first called). */ ++ ++extern int pthread_atfork (void (*__prepare) (void), ++ void (*__parent) (void), ++ void (*__child) (void)) __THROW; ++ ++ ++#ifdef __USE_EXTERN_INLINES ++/* Optimizations. */ ++__extern_inline int ++__NTH (pthread_equal (pthread_t __thread1, pthread_t __thread2)) ++{ ++ return __thread1 == __thread2; ++} ++#endif ++ ++__END_DECLS ++ ++#endif /* pthread.h */ +-- +2.30.0 + diff --git a/0002-elf-ld.so-add-testcase-for-ld.so-load-shared-object-.patch b/0002-elf-ld.so-add-testcase-for-ld.so-load-shared-object-.patch new file mode 100644 index 0000000000000000000000000000000000000000..9442241c4df4e8c197627c3c512945d45aad363e --- /dev/null +++ b/0002-elf-ld.so-add-testcase-for-ld.so-load-shared-object-.patch @@ -0,0 +1,1177 @@ +From 74c980c56a1ae533c3cd25f572f83c0c1def6a30 Mon Sep 17 00:00:00 2001 +From: Lv Ying +Date: Tue, 25 Jan 2022 09:25:35 +0000 +Subject: [PATCH 2/3] elf/ld.so: add testcase for ld.so load shared object use + hugepage feature + +1. testcase for hugepageedit +2. testcase for feature env +3. testcase for feature fallback +4. testcase for hugepage mmap consistency witch process occupancy +5. testcase for dlopen use hugepage +--- + config.make.in | 1 + + configure | 24 ++++++- + configure.ac | 3 + + elf/Makefile | 61 +++++++++++++++++ + elf/hugepageedit.c | 69 +++---------------- + elf/tst-check-hugepage.sh | 72 ++++++++++++++++++++ + elf/tst-dl-hugepage.sh | 70 +++++++++++++++++++ + elf/tst-dl-use-hugepage.c | 54 +++++++++++++++ + elf/tst-get-ephdr.h | 96 ++++++++++++++++++++++++++ + elf/tst-hugepageedit1.sh | 85 +++++++++++++++++++++++ + elf/tst-ld-hugepage-env.sh | 108 ++++++++++++++++++++++++++++++ + elf/tst-ld-hugepage-fallback.sh | 66 ++++++++++++++++++ + elf/tst-ld-hugepage-mmap-smaps.sh | 49 ++++++++++++++ + elf/tst-ld-hugepage.h | 7 ++ + elf/tst-ld-hugepagemod.c | 19 ++++++ + elf/tst-update-ehdr.c | 58 ++++++++++++++++ + elf/tst-update-phdr.c | 93 +++++++++++++++++++++++++ + elf/tst-use-hugepage.c | 15 +++++ + 18 files changed, 889 insertions(+), 61 deletions(-) + create mode 100644 elf/tst-check-hugepage.sh + create mode 100644 elf/tst-dl-hugepage.sh + create mode 100644 elf/tst-dl-use-hugepage.c + create mode 100644 elf/tst-get-ephdr.h + create mode 100644 elf/tst-hugepageedit1.sh + create mode 100644 elf/tst-ld-hugepage-env.sh + create mode 100644 elf/tst-ld-hugepage-fallback.sh + create mode 100644 elf/tst-ld-hugepage-mmap-smaps.sh + create mode 100644 elf/tst-ld-hugepage.h + create mode 100644 elf/tst-ld-hugepagemod.c + create mode 100644 elf/tst-update-ehdr.c + create mode 100644 elf/tst-update-phdr.c + create mode 100644 elf/tst-use-hugepage.c + +diff --git a/config.make.in b/config.make.in +index cbf59114..0105cc8e 100644 +--- a/config.make.in ++++ b/config.make.in +@@ -76,6 +76,7 @@ use-default-link = @use_default_link@ + have-cxx-thread_local = @libc_cv_cxx_thread_local@ + have-loop-to-function = @libc_cv_cc_loop_to_function@ + have-textrel_ifunc = @libc_cv_textrel_ifunc@ ++have-hugetlb-dir = @have_hugetlb_dir@ + + multi-arch = @multi_arch@ + +diff --git a/configure b/configure +index 43993923..be2277b1 100755 +--- a/configure ++++ b/configure +@@ -670,7 +670,7 @@ stack_protector + libc_cv_ssp + libc_cv_with_fp + base_machine +-enable_hugepage_shared_library ++have_hugetlb_dir + have_tunables + build_pt_chown + build_nscd +@@ -3848,6 +3848,28 @@ enable-hugepage-shared-library = $enable_hugepage_shared_library" + if test "$enable_hugepage_shared_library" = yes; then + $as_echo "#define HUGEPAGE_SHARED_LIB 1" >>confdefs.h + ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for /sys/devices/system/node/node0/hugepages/hugepages-2048kB/" >&5 ++$as_echo_n "checking for /sys/devices/system/node/node0/hugepages/hugepages-2048kB/... " >&6; } ++if ${ac_cv_file__sys_devices_system_node_node0_hugepages_hugepages_2048kB_+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ test "$cross_compiling" = yes && ++ as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 ++if test -r "/sys/devices/system/node/node0/hugepages/hugepages-2048kB/"; then ++ ac_cv_file__sys_devices_system_node_node0_hugepages_hugepages_2048kB_=yes ++else ++ ac_cv_file__sys_devices_system_node_node0_hugepages_hugepages_2048kB_=no ++fi ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_file__sys_devices_system_node_node0_hugepages_hugepages_2048kB_" >&5 ++$as_echo "$ac_cv_file__sys_devices_system_node_node0_hugepages_hugepages_2048kB_" >&6; } ++if test "x$ac_cv_file__sys_devices_system_node_node0_hugepages_hugepages_2048kB_" = xyes; then : ++ have_hugetlb_dir=yes ++else ++ have_hugetlb_dir=no ++fi ++ ++ + fi + + # We keep the original values in `$config_*' and never modify them, so we +diff --git a/configure.ac b/configure.ac +index 27a48338..fa34af26 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -487,6 +487,9 @@ AC_ARG_ENABLE([hugepage-shared-library], + LIBC_CONFIG_VAR([enable-hugepage-shared-library], [$enable_hugepage_shared_library]) + if test "$enable_hugepage_shared_library" = yes; then + AC_DEFINE(HUGEPAGE_SHARED_LIB) ++ AC_CHECK_FILE(/sys/devices/system/node/node0/hugepages/hugepages-2048kB/, ++ have_hugetlb_dir=yes, have_hugetlb_dir=no) ++ AC_SUBST(have_hugetlb_dir) + fi + + # We keep the original values in `$config_*' and never modify them, so we +diff --git a/elf/Makefile b/elf/Makefile +index 1574574d..0fb2be3b 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -213,6 +213,12 @@ others-pie += hugepageedit + install-bin += hugepageedit + + $(objpfx)hugepageedit: $(objpfx)hugepageedit.o ++ ++ifeq ($(run-built-tests),yes) ++tests-special += $(objpfx)tst-hugepageedit1.out $(objpfx)tst-ld-hugepage-env.out \ ++ $(objpfx)tst-ld-hugepage-fallback.out $(objpfx)tst-ld-hugepage-mmap-smaps.out \ ++ $(objpfx)tst-dl-hugepage.out ++endif + endif + + # To find xmalloc.c and xstrdup.c +@@ -788,6 +794,13 @@ $(objpfx)tst-gnu2-tls1: $(objpfx)tst-gnu2-tls1mod.so + tst-gnu2-tls1mod.so-no-z-defs = yes + CFLAGS-tst-gnu2-tls1mod.c += -mtls-dialect=gnu2 + endif ++ifeq (yes,$(enable-hugepage-shared-library)) ++ld-hugepagemod-suffixes = 1 2 3 4 5 ++ld-hugepagemod-modules = $(addprefix tst-ld-hugepagemod, $(ld-hugepagemod-suffixes)) ++tst-usehugepage = $(addprefix tst-use-hugepage, $(ld-hugepagemod-suffixes)) ++modules-names += $(ld-hugepagemod-modules) ++test-srcs += tst-update-ehdr tst-update-phdr tst-dl-use-hugepage $(tst-usehugepage) ++endif + ifeq (yes,$(have-protected-data)) + modules-names += tst-protected1moda tst-protected1modb + tests += tst-protected1a tst-protected1b +@@ -2015,6 +2028,54 @@ $(objpfx)tst-ldconfig-X.out : tst-ldconfig-X.sh $(objpfx)ldconfig + '$(run-program-env)' > $@; \ + $(evaluate-test) + ++ifeq (yes,$(enable-hugepage-shared-library)) ++CFLAGS-tst-ld-hugepagemod.c += -DOBJDIR=\"$(elf-objpfx)\" ++$(objpfx)tst-ld-hugepage-bin.o : ++ dd if=/dev/zero of=$@ count=4 bs=2MB ++$(patsubst %,$(objpfx)%.os,$(ld-hugepagemod-modules)): $(objpfx)tst-ld-hugepagemod%.os: tst-ld-hugepagemod.c $(objpfx)tst-ld-hugepage-bin.o ++ $(compile-command.c) -DN=$* ++$(patsubst %,$(objpfx)%.o,$(tst-usehugepage)): $(objpfx)tst-use-hugepage%.o: tst-use-hugepage.c ++ $(compile-command.c) ++$(patsubst tst-use-hugepage%,$(objpfx)tst-use-hugepage%,$(tst-usehugepage)): $(objpfx)tst-use-hugepage% : \ ++ $(objpfx)tst-use-hugepage%.o $(objpfx)tst-ld-hugepagemod%.so $(objpfx)ld.so ++$(objpfx)tst-dl-use-hugepage: $(libdl) ++ ++ifeq ($(have-hugetlb-dir),yes) ++$(objpfx)tst-hugepageedit1.out: tst-hugepageedit1.sh tst-check-hugepage.sh \ ++ $(objpfx)tst-update-ehdr $(objpfx)tst-use-hugepage1 $(objpfx)tst-ld-hugepagemod1.so ++ $(SHELL) $< '$(common-objpfx)' '$(test-wrapper)' \ ++ '$(test-wrapper-env)' $(CURDIR)/tst-check-hugepage.sh > $@; \ ++ $(evaluate-test) ++ ++$(objpfx)tst-ld-hugepage-env.out: tst-ld-hugepage-env.sh tst-check-hugepage.sh \ ++ $(objpfx)tst-use-hugepage2 $(objpfx)tst-ld-hugepagemod2.so ++ $(SHELL) $< '$(common-objpfx)' '$(test-wrapper)' \ ++ '$(test-wrapper-env)' $(CURDIR)/tst-check-hugepage.sh > $@; \ ++ $(evaluate-test) ++ ++$(objpfx)tst-ld-hugepage-fallback.out: tst-ld-hugepage-fallback.sh tst-check-hugepage.sh \ ++ $(objpfx)tst-update-phdr $(objpfx)tst-use-hugepage3 $(objpfx)tst-ld-hugepagemod3.so ++ $(SHELL) $< '$(common-objpfx)' '$(test-wrapper)' \ ++ '$(test-wrapper-env)' $(CURDIR)/tst-check-hugepage.sh > $@; \ ++ $(evaluate-test) ++ ++$(objpfx)tst-ld-hugepage-mmap-smaps.out: tst-ld-hugepage-mmap-smaps.sh tst-check-hugepage.sh \ ++ $(objpfx)tst-use-hugepage4 $(objpfx)tst-ld-hugepagemod4.so ++ $(SHELL) $< '$(common-objpfx)' '$(test-wrapper)' \ ++ '$(test-wrapper-env)' $(CURDIR)/tst-check-hugepage.sh > $@; \ ++ $(evaluate-test) ++ ++$(objpfx)tst-dl-hugepage.out: tst-dl-hugepage.sh tst-check-hugepage.sh \ ++ $(objpfx)tst-dl-use-hugepage $(objpfx)tst-ld-hugepagemod5.so ++ $(SHELL) $< '$(common-objpfx)' '$(test-wrapper)' \ ++ '$(test-wrapper-env)' $(CURDIR)/tst-check-hugepage.sh > $@; \ ++ $(evaluate-test) ++else ++tests-unsupported += tst-hugepageedit1.out tst-ld-hugepage-env.out tst-ld-hugepage-fallback.out \ ++ tst-ld-hugepage-mmap-smaps.out tst-dl-hugepage.out ++endif ++endif ++ + # Test static linking of all the libraries we can possibly link + # together. Note that in some configurations this may be less than the + # complete list of libraries we build but we try to maxmimize this list. +diff --git a/elf/hugepageedit.c b/elf/hugepageedit.c +index 14a91a4b..ab4247ad 100644 +--- a/elf/hugepageedit.c ++++ b/elf/hugepageedit.c +@@ -25,18 +25,10 @@ + #include + #include + #include ++#include "tst-get-ephdr.h" + +-/* reference kernel load_elf_phdrs program header table size constraint */ +-#define ELF_MIN_ALIGN 4096 + #define TOOL_NAME "hugepageedit" + +-int check_ptr(void *ptr, void *start, size_t len) +-{ +- if (ptr < start || ptr > start + len) +- return -1; +- return 0; +-} +- + void print_usage(void) + { + fprintf(stderr, "%s [-x] [-d] \n" \ +@@ -47,6 +39,7 @@ void print_usage(void) + + int main(int argc, char *argv[]) + { ++ size_t length; + int exit_status = -1; + int i, opt, delete = 0, exec_only = 0; + while ((opt = getopt(argc, argv, "dx")) != -1) +@@ -84,57 +77,13 @@ int main(int argc, char *argv[]) + return -1; + } + +- struct stat statbuf; +- if (fstat(fd, &statbuf) != 0) +- { +- perror("fstat"); +- goto close_fd; +- } +- +- /* this ensures file is large enough to hold ELF header */ +- if (statbuf.st_size < sizeof (ElfW(Ehdr))) +- { +- fprintf(stderr, "file is not large enough to hold ELF header\n"); +- goto close_fd; +- } +- +- void *ehdr = mmap(NULL, statbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); +- if (ehdr == MAP_FAILED) +- { +- perror("mmap"); +- goto close_fd; +- } +- +- if (memcmp(((ElfW(Ehdr) *) ehdr)->e_ident, ELFMAG, SELFMAG) != 0) +- { +- fprintf(stderr, "file is not ELF format\n"); +- goto unmap; +- } +- +- if (((ElfW(Ehdr) *)ehdr)->e_phentsize != sizeof(ElfW(Phdr))) +- { +- fprintf(stderr, "ELF header's e_phentsize mismatch ElfW(Phdr) size\n"); +- goto unmap; +- } +- +- unsigned int size = ((ElfW(Ehdr) *)ehdr)->e_phnum * sizeof(ElfW(Phdr)); +- if (size == 0 || size > ELF_MIN_ALIGN) +- { +- fprintf(stderr, "The program header table size specified by ELF header is abnormal: %u\n", size); +- goto unmap; +- } +- +- void *ephdr_s = ehdr + ((ElfW(Ehdr) *)ehdr)->e_phoff; +- void *ephdr_e = ehdr + ((ElfW(Ehdr) *)ehdr)->e_phoff + size; +- +- if (check_ptr(ephdr_s, ehdr, statbuf.st_size) || +- check_ptr(ephdr_e, ehdr, statbuf.st_size)) +- { +- fprintf(stderr, "ELF porgram header table is not fully mmaped\n"); +- goto unmap; +- } ++ void *ehdr = get_ehdr(fd, &length); ++ if (ehdr == NULL) ++ goto close_fd; + +- ElfW(Phdr) *phdr = (ElfW(Phdr) *)ephdr_s; ++ ElfW(Phdr) *phdr = (ElfW(Phdr) *)get_phdr(ehdr, length); ++ if (phdr == NULL) ++ goto unmap; + /* + * Here, mark hugepage flag in ELF header e_ident padding bytes won't work. + * elf/dl-load.c open_verify will check if shared object ELF header e_ident +@@ -160,7 +109,7 @@ int main(int argc, char *argv[]) + exit_status = 0; + + unmap: +- munmap(ehdr, statbuf.st_size); ++ munmap(ehdr, length); + + close_fd: + close(fd); +diff --git a/elf/tst-check-hugepage.sh b/elf/tst-check-hugepage.sh +new file mode 100644 +index 00000000..0cdebe2a +--- /dev/null ++++ b/elf/tst-check-hugepage.sh +@@ -0,0 +1,72 @@ ++#!/bin/sh ++# check whether ld.so use hugepage when loading shared object and whether ++# there are exceptions when using hugepage ++# Copyright (C) 2021-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 ++# . ++ ++check_hugepage_mmap () { ++ log=$1 ++ ++ cat $log | egrep "reserved area|_dl_map_segments_largein:" > /dev/null && return 0 ++ return 1 ++} ++ ++check_hugepage_mmap_success () { ++ log=$1 ++ ++ # check whether the log contains fallback log ++ cat $log | grep "_dl_map_segments_largein:" > /dev/null && return 1 ++ check_hugepage_mmap $log || return 1 ++ left=$(cat $log | grep _mmap_segment | wc -l) ++ right=$(cat $log | grep "} => mapseglen" | wc -l) ++ if [ $left -eq $right ]; then ++ return 0 ++ else ++ return 1 ++ fi ++} ++ ++check_hugepage_fallback () { ++ log=$1 ++ ++ cat $log | grep "_dl_map_segments_largein:" > /dev/null && return 0 ++ return 1 ++} ++ ++# return 0: mmap hugepage correctly ++# return 1: Non-hugepage mmap ++# return 2: mmap hugepage wrongly ++check_hugepage_mmap_detail () { ++ log=$1 ++ ++ # check whether the log contains hugepage mmap ++ areas=$(cat $log | grep "mmap hugepage:" | awk '{print $4}' | cut -d '[' -f2 | cut -d ')' -f1) ++ if test -z "$areas"; then ++ return 1 ++ else ++ for area in $areas; do ++ num=$(grep "mmap hugepage: \[$area)" $log | wc -l) ++ num=$(( $num * 2)) ++ total_num=$(grep $area $log | wc -l) ++ if [ $num -ne $total_num ]; then ++ return 2 ++ fi ++ grep -A21 $area $log | tail -22 ++ done ++ return 0 ++ fi ++} +diff --git a/elf/tst-dl-hugepage.sh b/elf/tst-dl-hugepage.sh +new file mode 100644 +index 00000000..f67e552f +--- /dev/null ++++ b/elf/tst-dl-hugepage.sh +@@ -0,0 +1,70 @@ ++#!/bin/sh ++# Test that ld.so can handle dlopen call ++# Copyright (C) 2021-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 ++# . ++ ++set -ex ++echo "source $4" ++source $4 ++ ++common_objpfx=$1 ++test_wrapper=$2 ++test_wrapper_env=$3 ++result=0 ++ ++excption_handle () ++{ ++ echo "ld.so hugepage feature is not behaving as expected, return $1" ++ result=1 ++} ++ ++check_global_var () ++{ ++ log=$1 ++ ++ for i in $(seq 1 2); do ++ cat $log | grep "In huge_func, huge_global = $i" > /dev/null|| return -1 ++ done ++ return 0 ++} ++ ++testroot="${common_objpfx}elf/dl-hugepage-directory" ++ ++rm -rf "$testroot" ++mkdir -p $testroot ++ ++echo '# reseve 200 2MB hugepage' ++echo 200 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages || exit 1 ++ ++echo '# Test LD_HUGEPAGE_LIB=1 whether ld.so mmap hugepage is consistent with the actual process occupancy' ++${test_wrapper_env} LD_HUGEPAGE_LIB=1 LD_DEBUG=files \ ++${test_wrapper} ${common_objpfx}elf/tst-dl-use-hugepage ${common_objpfx}elf/tst-ld-hugepagemod5.so > ${testroot}/log1 2>&1 ++check_hugepage_mmap_detail ${testroot}/log1 && rc=0 || rc=$? ++#check_global_var ${testroot}/log1 && rc=0 || rc=$? ++test $rc -eq 0 || excption_handle $rc ++ ++${test_wrapper_env} \ ++${test_wrapper} ${common_objpfx}elf/hugepageedit ${common_objpfx}elf/tst-ld-hugepagemod5.so || exit 1 ++ ++echo '# Test HUGEPAGE_PROBE=1 whether ld.so mmap hugepage is consistent with the actual process occupancy' ++${test_wrapper_env} HUGEPAGE_PROBE=1 LD_DEBUG=files \ ++${test_wrapper} ${common_objpfx}elf/tst-dl-use-hugepage ${common_objpfx}elf/tst-ld-hugepagemod5.so > ${testroot}/log2 2>&1 ++check_hugepage_mmap_detail ${testroot}/log2 && rc=0 || rc=$? ++#check_global_var ${testroot}/log2 && rc=0 || rc=$? ++test $rc -eq 0 || excption_handle $rc ++ ++exit $result +diff --git a/elf/tst-dl-use-hugepage.c b/elf/tst-dl-use-hugepage.c +new file mode 100644 +index 00000000..cd7c6f29 +--- /dev/null ++++ b/elf/tst-dl-use-hugepage.c +@@ -0,0 +1,54 @@ ++#include ++#include ++#include ++#include ++#include "tst-ld-hugepage.h" ++ ++#define DL_ERR_HANDLE(s) \ ++do { \ ++ fprintf(stderr, "%s: %s\n", s, dlerror()); \ ++ exit(EXIT_FAILURE); \ ++} while(0) ++ ++static void dl_flag_test(char *libname, int flags, int val) ++{ ++ int *global; ++ char *error; ++ void (*funcp)(void); ++ char command[100]; ++ sprintf(command, "cat /proc/%d/smaps", getpid()); ++ ++ void *handle = dlopen(libname, flags); ++ if (handle == NULL) ++ DL_ERR_HANDLE("dlopen"); ++ ++ (void) dlerror(); ++ ++ *(void **)(&global) = dlsym(handle, "huge_global"); ++ error = dlerror(); ++ if (error != NULL) ++ DL_ERR_HANDLE("dlsym"); ++ ++ (void) dlerror(); ++ *(void **)(&funcp) = dlsym(handle, "huge_func"); ++ error = dlerror(); ++ if (error != NULL) ++ DL_ERR_HANDLE("dlsym"); ++ ++ *global = val; ++ (*funcp)(); ++ system(command); ++ dlclose(handle); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ if (argc != 2) ++ { ++ fprintf(stderr, "shared object should be a parameter\n"); ++ exit(EXIT_FAILURE); ++ } ++ dl_flag_test(argv[1], RTLD_LAZY, 1); ++ dl_flag_test(argv[1], RTLD_NOW, 2); ++ return 0; ++} +diff --git a/elf/tst-get-ephdr.h b/elf/tst-get-ephdr.h +new file mode 100644 +index 00000000..109af265 +--- /dev/null ++++ b/elf/tst-get-ephdr.h +@@ -0,0 +1,96 @@ ++/* mmap ELF file return ELF header and get mmap length ++ Copyright (C) 1995-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 ++ . */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* reference kernel load_elf_phdrs program header table size constraint */ ++#define ELF_MIN_ALIGN 4096 ++ ++static __always_inline void *get_ehdr(int fd, size_t *len) ++{ ++ struct stat statbuf; ++ *len = 0; ++ if (fstat(fd, &statbuf) != 0) ++ { ++ perror("fstat"); ++ return NULL; ++ } ++ ++ /* this ensures file is large enough to hold ELF header */ ++ if (statbuf.st_size < sizeof (ElfW(Ehdr))) ++ { ++ fprintf(stderr, "file is not large enough to hold ELF header\n"); ++ return NULL; ++ } ++ ++ void *ehdr = mmap(NULL, statbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); ++ if (ehdr == MAP_FAILED) ++ { ++ perror("mmap"); ++ return NULL; ++ } ++ ++ if (memcmp(((ElfW(Ehdr) *) ehdr)->e_ident, ELFMAG, SELFMAG) != 0) ++ { ++ fprintf(stderr, "file is not ELF format\n"); ++ munmap(ehdr, statbuf.st_size); ++ ehdr = NULL; ++ } ++ ++ *len = statbuf.st_size; ++ return ehdr; ++} ++ ++static __always_inline int check_ptr(void *ptr, void *start, size_t len) ++{ ++ if (ptr < start || ptr > start + len) ++ return -1; ++ return 0; ++} ++ ++static __always_inline void *get_phdr(void *ehdr, size_t length) ++{ ++ if (((ElfW(Ehdr) *)ehdr)->e_phentsize != sizeof(ElfW(Phdr))) ++ { ++ fprintf(stderr, "ELF header's e_phentsize mismatch ElfW(Phdr) size\n"); ++ return NULL; ++ } ++ ++ unsigned int size = ((ElfW(Ehdr) *)ehdr)->e_phnum * sizeof(ElfW(Phdr)); ++ if (size == 0 || size > ELF_MIN_ALIGN) ++ { ++ fprintf(stderr, "The program header table size specified by ELF header is abnormal: %u\n", size); ++ return NULL; ++ } ++ ++ void *ephdr_s = ehdr + ((ElfW(Ehdr) *)ehdr)->e_phoff; ++ void *ephdr_e = ehdr + ((ElfW(Ehdr) *)ehdr)->e_phoff + size; ++ ++ if (check_ptr(ephdr_s, ehdr, length) || ++ check_ptr(ephdr_e, ehdr, length)) ++ { ++ fprintf(stderr, "ELF porgram header table is not fully mmaped\n"); ++ return NULL; ++ } ++ ++ return ephdr_s; ++} +diff --git a/elf/tst-hugepageedit1.sh b/elf/tst-hugepageedit1.sh +new file mode 100644 +index 00000000..ee43c279 +--- /dev/null ++++ b/elf/tst-hugepageedit1.sh +@@ -0,0 +1,85 @@ ++#!/bin/sh ++# Test that hugepageedit can handle abnormal files reasonably ++# Copyright (C) 2021-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 ++# . ++ ++set -ex ++echo "source $4" ++source $4 ++ ++common_objpfx=$1 ++test_wrapper=$2 ++test_wrapper_env=$3 ++result=0 ++ ++excption_handle () ++{ ++ echo "hugepageedit and ls.so use hugepage feature is not beahving expected" ++ result=1 ++} ++ ++testroot="${common_objpfx}elf/hugepageedit-test-directory" ++ ++rm -rf "$testroot" ++mkdir -p $testroot ++cp ${common_objpfx}elf/tst-use-hugepage1 $testroot/tst-use-hugepage1 ++ ++echo '# reseve 200 2MB hugepage' ++echo 200 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages || exit 1 ++ ++echo '# Test no option hugepageedit' ++${test_wrapper_env} \ ++${test_wrapper} ${common_objpfx}elf/hugepageedit ${common_objpfx}elf/tst-ld-hugepagemod1.so || exit 1 ++${test_wrapper_env} HUGEPAGE_PROBE=1 LD_DEBUG=files \ ++${test_wrapper} ${common_objpfx}elf/tst-use-hugepage1 > ${testroot}/log1 2>&1 ++check_hugepage_mmap_success ${testroot}/log1 && rc=0 || rc=$? ++test $rc -eq 0 || excption_handle ++ ++echo '# Test hugepageedit -d option' ++${test_wrapper_env} \ ++${test_wrapper} ${common_objpfx}elf/hugepageedit -d ${common_objpfx}elf/tst-ld-hugepagemod1.so || exit 1 ++${test_wrapper_env} HUGEPAGE_PROBE=1 LD_DEBUG=files \ ++${test_wrapper} ${common_objpfx}elf/tst-use-hugepage1 > ${testroot}/log2 2>&1 ++check_hugepage_mmap ${testroot}/log2 && rc=1 || rc=0 ++test $rc -eq 0 || excption_handle ++ ++echo '# Test hugepageedit -x option' ++${test_wrapper_env} \ ++${test_wrapper} ${common_objpfx}elf/hugepageedit -x ${common_objpfx}elf/tst-ld-hugepagemod1.so || exit 1 ++${test_wrapper_env} HUGEPAGE_PROBE=1 LD_DEBUG=files \ ++${test_wrapper} ${common_objpfx}elf/tst-use-hugepage1 > ${testroot}/log3 2>&1 ++check_hugepage_mmap_success ${testroot}/log3 && rc=0 || rc=$? ++test $rc -eq 0 || excption_handle ++ ++echo '# Test Non-ELF file' ++dd if=/dev/urandom of=${testroot}/test.file count=1024 bs=1024 ++${test_wrapper_env} \ ++${test_wrapper} ${common_objpfx}elf/hugepageedit ${testroot}/test.file 2>&1 && result=1 ++ ++echo '# Test ELF phnum is 0' ++${test_wrapper_env} \ ++${test_wrapper} ${common_objpfx}elf/tst-update-ehdr ${testroot}/tst-use-hugepage1 0 2>&1 || result=1 ++${test_wrapper_env} \ ++${test_wrapper} ${common_objpfx}elf/hugepageedit ${testroot}/tst-use-hugepage1 2>&1 && result=1 ++ ++echo '# Test ELF phnum is 0xFFFF' ++${test_wrapper_env} \ ++${test_wrapper} ${common_objpfx}elf/tst-update-ehdr ${testroot}/tst-use-hugepage1 65535 2>&1 || result=1 ++${test_wrapper_env} \ ++${test_wrapper} ${common_objpfx}elf/hugepageedit ${testroot}/tst-use-hugepage1 2>&1 && result=1 ++ ++exit $result +diff --git a/elf/tst-ld-hugepage-env.sh b/elf/tst-ld-hugepage-env.sh +new file mode 100644 +index 00000000..e16ada67 +--- /dev/null ++++ b/elf/tst-ld-hugepage-env.sh +@@ -0,0 +1,108 @@ ++#!/bin/sh ++# Test that ld.so can handle different env input ++# Copyright (C) 2021-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 ++# . ++ ++set -ex ++echo "source $4" ++source $4 ++ ++common_objpfx=$1 ++test_wrapper=$2 ++test_wrapper_env=$3 ++result=0 ++ ++excption_handle () ++{ ++ echo "ld.so hugepage feature is not behaving as expected" ++ result=1 ++} ++ ++testroot="${common_objpfx}elf/ld-hugepage-env-directory" ++ ++rm -rf "$testroot" ++mkdir -p $testroot ++ ++echo '# reseve 200 2MB hugepage' ++echo 200 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages || exit 1 ++ ++${test_wrapper_env} \ ++${test_wrapper} ${common_objpfx}elf/hugepageedit -d ${common_objpfx}elf/tst-ld-hugepagemod2.so || exit 1 ++ ++echo '# Test HUGEPAGE_PROBE env set 1 and shared object is not hugepageedited' ++${test_wrapper_env} HUGEPAGE_PROBE=1 LD_DEBUG=files \ ++${test_wrapper} ${common_objpfx}elf/tst-use-hugepage2 > ${testroot}/log1 2>&1 ++check_hugepage_mmap ${testroot}/log1 && rc=1 || rc=0 ++test $rc -eq 0 || excption_handle ++ ++echo '# Test LD_HUGEPAGE_LIB env set 1 and shared object is not hugepageedited' ++${test_wrapper_env} LD_HUGEPAGE_LIB=1 LD_DEBUG=files \ ++${test_wrapper} ${common_objpfx}elf/tst-use-hugepage2 > ${testroot}/log2 2>&1 ++check_hugepage_mmap_success ${testroot}/log2 && rc=0 || rc=$? ++test $rc -eq 0 || excption_handle ++ ++echo '# Test LD_HUGEPAGE_LIB env set 100 and shared object is not hugepageedited' ++${test_wrapper_env} LD_HUGEPAGE_LIB=100 LD_DEBUG=files \ ++${test_wrapper} ${common_objpfx}elf/tst-use-hugepage2 > ${testroot}/log3 2>&1 ++check_hugepage_mmap ${testroot}/log3 && rc=1 || rc=0 ++test $rc -eq 0 || excption_handle ++ ++echo '# Test LD_HUGEPAGE_LIB env set -8 and shared object is not hugepageedited' ++${test_wrapper_env} LD_HUGEPAGE_LIB=-8 LD_DEBUG=files \ ++${test_wrapper} ${common_objpfx}elf/tst-use-hugepage2 > ${testroot}/log4 2>&1 ++check_hugepage_mmap ${testroot}/log4 && rc=1 || rc=0 ++test $rc -eq 0 || excption_handle ++ ++echo '# Test LD_HUGEPAGE_LIB env set aa#_bb and shared object is not hugepageedited' ++${test_wrapper_env} LD_HUGEPAGE_LIB=aa#_bb LD_DEBUG=files \ ++${test_wrapper} ${common_objpfx}elf/tst-use-hugepage2 > ${testroot}/log5 2>&1 ++check_hugepage_mmap ${testroot}/log5 && rc=1 || rc=0 ++test $rc -eq 0 || excption_handle ++ ++${test_wrapper_env} \ ++${test_wrapper} ${common_objpfx}elf/hugepageedit ${common_objpfx}elf/tst-ld-hugepagemod2.so || exit 1 ++echo '# Test HUGEPAGE_PROBE env set 2 and shared object is hugepageedited' ++${test_wrapper_env} HUGEPAGE_PROBE=2 LD_DEBUG=files \ ++${test_wrapper} ${common_objpfx}elf/tst-use-hugepage2 > ${testroot}/log6 2>&1 ++check_hugepage_mmap_success ${testroot}/log6 && rc=0 || rc=$? ++test $rc -eq 0 || excption_handle ++ ++echo '# Test HUGEPAGE_PROBE env set -2 and shared object is hugepageedited' ++${test_wrapper_env} HUGEPAGE_PROBE=-2 LD_DEBUG=files \ ++${test_wrapper} ${common_objpfx}elf/tst-use-hugepage2 > ${testroot}/log7 2>&1 ++check_hugepage_mmap_success ${testroot}/log7 && rc=0 || rc=$? ++test $rc -eq 0 || excption_handle ++ ++echo '# Test HUGEPAGE_PROBE env set 0 and shared object is hugepageedited' ++${test_wrapper_env} HUGEPAGE_PROBE=0 LD_DEBUG=files \ ++${test_wrapper} ${common_objpfx}elf/tst-use-hugepage2 > ${testroot}/log8 2>&1 ++check_hugepage_mmap_success ${testroot}/log8 && rc=0 || rc=$? ++test $rc -eq 0 || excption_handle ++ ++echo '# Test HUGEPAGE_PROBE env set 3.14 and shared object is hugepageedited' ++${test_wrapper_env} HUGEPAGE_PROBE=3.14 LD_DEBUG=files \ ++${test_wrapper} ${common_objpfx}elf/tst-use-hugepage2 > ${testroot}/log9 2>&1 ++check_hugepage_mmap_success ${testroot}/log9 && rc=0 || rc=$? ++test $rc -eq 0 || excption_handle ++ ++echo '# Test HUGEPAGE_PROBE env set #aabb and shared object is hugepageedited' ++${test_wrapper_env} HUGEPAGE_PROBE=#aabb LD_DEBUG=files \ ++${test_wrapper} ${common_objpfx}elf/tst-use-hugepage2 > ${testroot}/log10 2>&1 ++check_hugepage_mmap_success ${testroot}/log10 && rc=0 || rc=$? ++test $rc -eq 0 || excption_handle ++ ++exit $result +diff --git a/elf/tst-ld-hugepage-fallback.sh b/elf/tst-ld-hugepage-fallback.sh +new file mode 100644 +index 00000000..0c616633 +--- /dev/null ++++ b/elf/tst-ld-hugepage-fallback.sh +@@ -0,0 +1,66 @@ ++#!/bin/sh ++# Test that ld.so can fallback to original shared object load process when ++# exception happens ++# Copyright (C) 2021-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 ++# . ++ ++echo "source $4" ++source $4 ++ ++common_objpfx=$1 ++test_wrapper=$2 ++test_wrapper_env=$3 ++result=0 ++ ++excption_handle () ++{ ++ echo "ld.so hugepage feature should fallback this time" ++ result=1 ++} ++ ++testroot="${common_objpfx}elf/ld-hugepage-fallback" ++ ++rm -rf "$testroot" ++mkdir -p $testroot ++ ++echo '# reseve 200 2MB hugepage' ++echo 200 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages || exit 1 ++ ++${test_wrapper_env} \ ++${test_wrapper} ${common_objpfx}elf/hugepageedit -d ${common_objpfx}elf/tst-ld-hugepagemod3.so || exit 1 ++ ++echo '# tst-update-phdr make shared object previous PT_LOAD segment vma > next' ++${test_wrapper_env} \ ++${test_wrapper} ${common_objpfx}elf/tst-update-phdr ${common_objpfx}elf/tst-ld-hugepagemod3.so || exit 1 ++ ++echo '# Test LD_HUGEPAGE_LIB env set 1 and shared object is not hugepageedited' ++${test_wrapper_env} LD_HUGEPAGE_LIB=1 LD_DEBUG=files \ ++${test_wrapper} ${common_objpfx}elf/tst-use-hugepage3 > ${testroot}/log1 2>&1 ++check_hugepage_fallback ${testroot}/log1 && rc=0 || rc=$? ++test $rc -eq 0 || excption_handle ++ ++echo '# hugepageedit shared object' ++${test_wrapper_env} \ ++${test_wrapper} ${common_objpfx}elf/hugepageedit ${common_objpfx}elf/tst-ld-hugepagemod3.so || exit 1 ++ ++echo '# Test HUGEPAGE_PROBE env set 1 and shared object is hugepageedited' ++${test_wrapper_env} HUGEPAGE_PROBE=1 LD_DEBUG=files \ ++${test_wrapper} ${common_objpfx}elf/tst-use-hugepage3 > ${testroot}/log2 2>&1 ++check_hugepage_fallback ${testroot}/log2 && rc=0 || rc=$? ++test $rc -eq 0 || excption_handle ++ ++exit $result +diff --git a/elf/tst-ld-hugepage-mmap-smaps.sh b/elf/tst-ld-hugepage-mmap-smaps.sh +new file mode 100644 +index 00000000..b817ab53 +--- /dev/null ++++ b/elf/tst-ld-hugepage-mmap-smaps.sh +@@ -0,0 +1,49 @@ ++#!/bin/sh ++# Test that ld.so mmapping hugepage is consistent with the actual process occupancy ++# Copyright (C) 2021-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 ++# . ++ ++set -ex ++echo "source $4" ++source $4 ++ ++common_objpfx=$1 ++test_wrapper=$2 ++test_wrapper_env=$3 ++result=0 ++ ++excption_handle () ++{ ++ echo "ld.so mmap hugepage is not consistent with the actual process occupancy, return $1" ++ result=1 ++} ++ ++testroot="${common_objpfx}elf/ld-hugepage-mmap-smaps" ++ ++rm -rf "$testroot" ++mkdir -p $testroot ++ ++echo '# reseve 200 2MB hugepage' ++echo 200 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages || exit 1 ++ ++echo '# Test LD_HUGEPAGE_LIB=1 whether ld.so mmap hugepage is consistent with the actual process occupancy' ++${test_wrapper_env} LD_HUGEPAGE_LIB=1 LD_DEBUG=files \ ++${test_wrapper} ${common_objpfx}elf/tst-use-hugepage4 > ${testroot}/log1 2>&1 ++check_hugepage_mmap_detail ${testroot}/log1 && rc=0 || rc=$? ++test $rc -eq 0 || excption_handle $rc ++ ++exit $result +diff --git a/elf/tst-ld-hugepage.h b/elf/tst-ld-hugepage.h +new file mode 100644 +index 00000000..30e938da +--- /dev/null ++++ b/elf/tst-ld-hugepage.h +@@ -0,0 +1,7 @@ ++#ifndef TST_HUGEPAGE_H ++#define TST_HUGEPAGE_H ++ ++extern void huge_func(void); ++extern int huge_global; ++ ++#endif +diff --git a/elf/tst-ld-hugepagemod.c b/elf/tst-ld-hugepagemod.c +new file mode 100644 +index 00000000..70c42e5a +--- /dev/null ++++ b/elf/tst-ld-hugepagemod.c +@@ -0,0 +1,19 @@ ++#include ++ ++#define BIN_PATH OBJDIR"/tst-ld-hugepage-bin.o" ++ ++int huge_global; ++ ++asm (".section .rodata\n\t" \ ++ ".globl vvvdso_start, vvvdso_end\n" \ ++ ".balign 4096\n" \ ++ "vvvdso_start:\n\t" \ ++ ".incbin " "\""BIN_PATH"\"" "\n\t" \ ++ ".balign 4096\n" \ ++ "vvvdso_end:\n\t" \ ++ ".previous"); ++ ++void huge_func(void) ++{ ++ printf("In huge_func, huge_global = %d\n", huge_global); ++} +diff --git a/elf/tst-update-ehdr.c b/elf/tst-update-ehdr.c +new file mode 100644 +index 00000000..6d653aa0 +--- /dev/null ++++ b/elf/tst-update-ehdr.c +@@ -0,0 +1,58 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "tst-get-ephdr.h" ++ ++#define TOOL_NAME "tst-update-ehdr" ++ ++void print_usage(void) ++{ ++ fprintf(stderr, "%s \n", TOOL_NAME); ++} ++ ++int main(int argc, char **argv) ++{ ++ size_t length; ++ int exit_status = EXIT_FAILURE; ++ ++ if (argc != 3) ++ { ++ print_usage(); ++ exit(EXIT_FAILURE); ++ } ++ ++ int fd = open(argv[1], O_RDWR); ++ if (fd < 0) ++ { ++ perror("open"); ++ exit(EXIT_FAILURE); ++ } ++ ++ void *ehdr = get_ehdr(fd, &length); ++ if (ehdr == NULL) ++ goto close_fd; ++ ++ char *endptr; ++ unsigned long val = strtoul(argv[2], &endptr, 10); ++ if ((errno == ERANGE && val == ULONG_MAX) || (errno != 0 && val == 0)) ++ { ++ perror("strtoul"); ++ goto unmap; ++ } ++ ++ ((ElfW(Ehdr) *)ehdr)->e_phnum = val; ++ exit_status = EXIT_SUCCESS; ++ ++unmap: ++ munmap(ehdr, length); ++ ++close_fd: ++ close(fd); ++ ++ exit(exit_status); ++} +diff --git a/elf/tst-update-phdr.c b/elf/tst-update-phdr.c +new file mode 100644 +index 00000000..bd3e30eb +--- /dev/null ++++ b/elf/tst-update-phdr.c +@@ -0,0 +1,93 @@ ++/* construct exception PT_LOAD segment VMA ++ make previous PT_LOAD vma > next PT_LOAD vma ++ Copyright (C) 2021-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 ++ . */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "tst-get-ephdr.h" ++ ++#define TOOL_NAME "tst-update-phdr" ++#define PAGE_SIZE 0x1000 ++ ++void print_usage(void) ++{ ++ fprintf(stderr, "%s \n", TOOL_NAME); ++} ++ ++int main(int argc, char **argv) ++{ ++ size_t length; ++ int exit_status = EXIT_FAILURE; ++ int i; ++ if (argc != 2) ++ { ++ print_usage(); ++ exit(EXIT_FAILURE); ++ } ++ ++ int fd = open(argv[1], O_RDWR); ++ if (fd < 0) ++ { ++ perror("open"); ++ exit(EXIT_FAILURE); ++ } ++ ++ void *ehdr = get_ehdr(fd, &length); ++ if (ehdr == NULL) ++ goto close_fd; ++ ++ ElfW(Phdr) *phdr = (ElfW(Phdr) *)get_phdr(ehdr, length); ++ if (phdr == NULL) ++ goto unmap; ++ ++ ElfW(Phdr) *prev =NULL, *next = NULL; ++ for (i = 0; i < ((ElfW(Ehdr) *)ehdr)->e_phnum; i++) ++ { ++ if (prev != NULL && next != NULL) ++ break; ++ if (phdr[i].p_type == PT_LOAD) ++ { ++ if (prev == NULL) ++ prev = &phdr[i]; ++ else ++ next = &phdr[i]; ++ } ++ } ++ if (prev != NULL && next != NULL) ++ { ++ prev->p_vaddr = next->p_vaddr + PAGE_SIZE; ++ exit_status = EXIT_SUCCESS; ++ } ++ else ++ fprintf(stderr, "There are no PT_LOADs in %s\n", argv[1]); ++ ++unmap: ++ munmap(ehdr, length); ++ ++close_fd: ++ close(fd); ++ ++ exit(exit_status); ++} +diff --git a/elf/tst-use-hugepage.c b/elf/tst-use-hugepage.c +new file mode 100644 +index 00000000..938e0afc +--- /dev/null ++++ b/elf/tst-use-hugepage.c +@@ -0,0 +1,15 @@ ++#include ++#include ++#include ++#include "tst-ld-hugepage.h" ++ ++int main(void) ++{ ++ char command[100]; ++ sprintf(command, "cat /proc/%d/smaps", getpid()); ++ system(command); ++ huge_func(); ++ huge_global = 1; ++ huge_func(); ++ return 0; ++} +-- +2.31.1 + diff --git a/0003-add-build-script-and-files-of-libpthread_2_17_so.patch b/0003-add-build-script-and-files-of-libpthread_2_17_so.patch new file mode 100644 index 0000000000000000000000000000000000000000..75ca704342b731a9f6445ac8a2e712d65bc24a1d --- /dev/null +++ b/0003-add-build-script-and-files-of-libpthread_2_17_so.patch @@ -0,0 +1,135 @@ +From 7cb15fbef45361db6ad718077a4f0a6d2dc845f2 Mon Sep 17 00:00:00 2001 +From: Yang Yanchao +Date: Wed Nov 24 09:31:31 2021 +0800 +Subject: [PATCH 3/9] build extra lipthreadcond so + +Add the build script and file of libpthread-2.17.so + +--- + nptl_2_17/Makefile | 52 +++++++++++++++++++++++++++ + nptl_2_17/build_libpthread-2.17.so.sh | 10 ++++++ + nptl_2_17/libpthread-2.17-aarch64.map | 14 ++++++++ + nptl_2_17/libpthread-2.17-x86_64.map | 14 ++++++++ + 4 files changed, 90 insertions(+) + create mode 100644 nptl_2_17/Makefile + create mode 100644 nptl_2_17/build_libpthread-2.17.so.sh + create mode 100644 nptl_2_17/libpthread-2.17-aarch64.map + create mode 100644 nptl_2_17/libpthread-2.17-x86_64.map + +diff --git a/nptl_2_17/Makefile b/nptl_2_17/Makefile +new file mode 100644 +index 00000000..f248ce56 +--- /dev/null ++++ b/nptl_2_17/Makefile +@@ -0,0 +1,52 @@ ++include libpthread-2.17_config ++subdir=libpthread-2.17 ++objdir=../$(build_dir)/ ++ ++ ++ifdef subdir ++.. := ../ ++endif ++ ++objpfx := $(patsubst %//,%/,$(objdir)/$(subdir)/) ++common-objpfx = $(objdir)/ ++common-objdir = $(objdir) ++ ++sysdep_dir := $(..)sysdeps ++export sysdep_dir := $(sysdep_dir) ++ ++include $(common-objpfx)soversions.mk ++include $(common-objpfx)config.make ++ ++uses-callbacks = -fexceptions ++ ++sysdirs := $(foreach D,$(config-sysdirs),$(firstword $(filter /%,$D) $(..)$D)) ++ +++sysdep_dirs = $(sysdirs) +++sysdep_dirs := $(objdir) $(+sysdep_dirs) ++ +++sysdep-includes := $(foreach dir,$(+sysdep_dirs), $(addprefix -I,$(wildcard $(dir)/include) $(dir))) ++ ++compile_obj = pthread_cond_wait_2_17.os pthread_cond_signal_2_17.os pthread_cond_broadcast_2_17.os pthread_cond_init_2_17.os pthread_cond_destroy_2_17.os pthread_condattr_getclock_2_17.os pthread_condattr_getpshared_2_17.os pthread_condattr_init_2_17.os pthread_condattr_setclock_2_17.os cleanup_compat_2_17.os pthread_mutex_lock_2_17.os pthread_mutex_unlock_2_17.os tpp_2_17.os vars_2_17.os pause_nocancel_2_17.os lll_timedlock_wait_2_17.os pthread_mutex_cond_lock_2_17.os cancellation_2_17.os lowlevellock_2_17.os unwind_2_17.os ++ ++ifeq (x86_64, $(arch)) ++compile_obj += elision-timed_2_17.os elision-trylock_2_17.os elision-lock_2_17.os elision-unlock_2_17.os ++endif ++ ++exist_obj_dir = $(foreach n,$(exist_obj),../$(build_dir)/nptl/$(n)) ++ ++compile_obj_dir = $(foreach n,$(compile_obj),../$(build_dir)/nptl/$(n)) ++ ++CFLAGS = -c -std=gnu11 -fgnu89-inline -fPIE -DNDEBUG -O2 -Wall -Werror -Wp,-D_GLIBCXX_ASSERTIONS -Wundef -Wwrite-strings -fasynchronous-unwind-tables -fmerge-all-constants -frounding-math -fstack-clash-protection -fstack-protector-strong -g -mtune=generic -Wstrict-prototypes -Wold-style-definition -fno-math-errno -fPIC -fexceptions -fasynchronous-unwind-tables -ftls-model=initial-exec -D_FORTIFY_SOURCE=2 -DSHARED -DTOP_NAMESPACE=glibc ++ ++Headers = -I../include -I../$(build_dir)/nptl $(+sysdep-includes) -I../nptl_2_17 -I../nptl -I../libio -I../. -D_LIBC_REENTRANT -include ../$(build_dir)/libc-modules.h -include include/libc-symbols.h ++ ++all: libpthread-2.17.so ++ ++libpthread-2.17.so : $(compile_obj) libpthread-2.17_pic.a ++ gcc -shared -static-libgcc -Wl,-O1 -Wl,-z,defs -Wl,-dynamic-linker=/usr/local/lib/$(ld.so-version) -B../$(build_dir)/csu/ -Wl,--version-script=libpthread-2.17-$(arch).map -Wl,-soname=libpthread-2.17.so.0 -Wl,-z,noexecstack -Wtrampolines -Wl,-z,combreloc -Wl,-z,relro -Wl,--hash-style=both -Wl,-z,now -Wl,--enable-new-dtags,-z,nodelete,-z,initfirst -L../$(build_dir) -L../$(build_dir)/math -L../$(build_dir)/elf -L../$(build_dir)/dlfcn -L../$(build_dir)/nss -L../$(build_dir)/nis -L../$(build_dir)/rt -L../$(build_dir)/resolv -L../$(build_dir)/mathvec -L../$(build_dir)/support -L../$(build_dir)/crypt -L../$(build_dir)/nptl -Wl,-rpath-link=../$(build_dir):../$(build_dir)/math:../$(build_dir)/elf:../$(build_dir)/dlfcn:../$(build_dir)/nss:../$(build_dir)/nis:../$(build_dir)/rt:../$(build_dir)/resolv:../$(build_dir)/mathvec:../$(build_dir)/support:../$(build_dir)/crypt:../$(build_dir)/nptl -o ../$(build_dir)/nptl/libpthread-2.17.so ../$(build_dir)/csu/abi-note.o -Wl,--whole-archive ../$(build_dir)/nptl/libpthread-2.17_pic.a -Wl,--no-whole-archive -Wl,--start-group ../$(build_dir)/libc.so ../$(build_dir)/libc_nonshared.a -Wl,--as-needed ../$(build_dir)/elf/ld.so -Wl,--no-as-needed -Wl,--end-group ++ ++libpthread-2.17_pic.a : $(compile_obj_dir) $(exist_obj_dir) ++ ar cruv ../$(build_dir)/nptl/$@ $^ ++ ++$(compile_obj) : %.os : %.c ++ gcc $< $(CFLAGS) $(Headers) -o ../$(build_dir)/nptl/$@ -MD -MP -MF ../$(build_dir)/nptl/$@.dt -MT ../$(build_dir)/nptl/$@ +diff --git a/nptl_2_17/build_libpthread-2.17.so.sh b/nptl_2_17/build_libpthread-2.17.so.sh +new file mode 100644 +index 00000000..bdb97d0f +--- /dev/null ++++ b/nptl_2_17/build_libpthread-2.17.so.sh +@@ -0,0 +1,10 @@ ++#!/bin/sh ++set -e ++build_arch=$1 ++build_dir=$2 ++config_dir=libpthread-2.17_config ++ ++echo arch=${build_arch} > ${config_dir} ++echo build_dir=${build_dir} >> ${config_dir} ++make ++rm -rf ${config_dir} +diff --git a/nptl_2_17/libpthread-2.17-aarch64.map b/nptl_2_17/libpthread-2.17-aarch64.map +new file mode 100644 +index 00000000..2c49fe17 +--- /dev/null ++++ b/nptl_2_17/libpthread-2.17-aarch64.map +@@ -0,0 +1,14 @@ ++GLIBC_2.17 { ++ global: ++ pthread_cond_init; pthread_cond_destroy; ++ pthread_cond_signal; pthread_cond_broadcast; ++ pthread_cond_wait; pthread_cond_timedwait; ++ local: ++ *; ++}; ++GLIBC_2.34 { ++ global: ++ pthread_cond_clockwait; ++ local: ++ *; ++}; +diff --git a/nptl_2_17/libpthread-2.17-x86_64.map b/nptl_2_17/libpthread-2.17-x86_64.map +new file mode 100644 +index 00000000..b01e7d0d +--- /dev/null ++++ b/nptl_2_17/libpthread-2.17-x86_64.map +@@ -0,0 +1,14 @@ ++GLIBC_2.3.2 { ++ global: ++ pthread_cond_init; pthread_cond_destroy; ++ pthread_cond_signal; pthread_cond_broadcast; ++ pthread_cond_wait; pthread_cond_timedwait; ++ local: ++ *; ++}; ++GLIBC_2.34 { ++ global: ++ pthread_cond_clockwait; ++ local: ++ *; ++}; +-- +2.30.0 + diff --git a/0003-elf-ld.so-use-special-mmap-for-hugepage-to-get-symbo.patch b/0003-elf-ld.so-use-special-mmap-for-hugepage-to-get-symbo.patch new file mode 100644 index 0000000000000000000000000000000000000000..8b67e66472ed4e72fb6bc5bf580e9dba2d3637e3 --- /dev/null +++ b/0003-elf-ld.so-use-special-mmap-for-hugepage-to-get-symbo.patch @@ -0,0 +1,69 @@ +From 49986b3674d002c43fa09e6b777555bdc772018b Mon Sep 17 00:00:00 2001 +From: Lv Ying +Date: Tue, 25 Jan 2022 09:29:32 +0000 +Subject: [PATCH 3/3] elf/ld.so: use special mmap for hugepage to get symbols + +use special mmap for hugepage to get symbols in hugepage area for debug +purpose; kernel need to support file mmap hugepage; +--- + elf/dl-load.h | 2 -- + elf/dl-map-segments-hugepage.h | 25 +++---------------------- + 2 files changed, 3 insertions(+), 24 deletions(-) + +diff --git a/elf/dl-load.h b/elf/dl-load.h +index d3f69466..fcf91a47 100644 +--- a/elf/dl-load.h ++++ b/elf/dl-load.h +@@ -134,8 +134,6 @@ static const char *_dl_map_segments (struct link_map *l, int fd, + #ifdef HUGEPAGE_SHARED_LIB + #define DL_MAP_SEGMENTS_ERROR_TYPE \ + N_("cannot map Non shared object file in hugepage") +-#define DL_MAP_SEGMENTS_ERROR_READ_SEGMENT \ +- N_("failed to read shared object file") + #define DL_MAP_SEGMENTS_ERROR_ARRANGE \ + N_("shared object's PT_LOAD segment in wrong arrange") + #define DL_MAP_SEGMENTS_ERROR_MAP_HOLE_FILL \ +diff --git a/elf/dl-map-segments-hugepage.h b/elf/dl-map-segments-hugepage.h +index cd7b6d79..37788ef9 100644 +--- a/elf/dl-map-segments-hugepage.h ++++ b/elf/dl-map-segments-hugepage.h +@@ -302,33 +302,14 @@ _mmap_segment_filesz(struct link_map *l, const struct loadcmd *c, ElfW(Addr) map + + size_t mod = len % SIZE_2MB; + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) +- _dl_debug_printf("\t\tmmap hugepage: [%lx-%lx)\n", mapstart, mapstart + len - mod); ++ _dl_debug_printf("\t\tmmap hugepage: [%lx-%lx), mapoff = %lx\n", mapstart, ++ mapstart + len - mod, c->mapoff + relro_len + prev_map_len); + mapstart = (ElfW(Addr))__mmap((void *)mapstart, len - mod, c->prot, + MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB|(SHFIT_2MB << MAP_HUGE_SHIFT), +- -1, 0); ++ fd, c->mapoff + relro_len + prev_map_len); + if (__glibc_unlikely ((void *)mapstart == MAP_FAILED)) + return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT; + +- if ((c->prot & PROT_WRITE) == 0 && __mprotect((void *)mapstart, len - mod, c->prot | PROT_WRITE) < 0) +- { +- return DL_MAP_SEGMENTS_ERROR_MPROTECT; +- } +- +- /* Read the segment contents from the file. */ +- size_t file_len = (size_t)(c->dataend - c->mapstart) <= prev_map_len + relro_len ? 0 : +- (size_t)(c->dataend - c->mapstart) - prev_map_len - relro_len; +- if (file_len > 0) +- { +- lseek(fd, c->mapoff + relro_len + prev_map_len, SEEK_SET); +- if ( __read(fd, (void *)mapstart, file_len < len - mod ? file_len : len - mod) < 0) +- return DL_MAP_SEGMENTS_ERROR_READ_SEGMENT; +- } +- +- if ((c->prot & PROT_WRITE) == 0 && __mprotect((void *)mapstart, len - mod, c->prot) < 0) +- { +- return DL_MAP_SEGMENTS_ERROR_MPROTECT; +- } +- + map_addr = map_addr == 0 ? (void *)mapstart : map_addr; + mapstart += len - mod; + +-- +2.31.1 + diff --git a/0004-add-two-header-files-with-some-deleted-macros.patch b/0004-add-two-header-files-with-some-deleted-macros.patch new file mode 100644 index 0000000000000000000000000000000000000000..7acb8e2a42827573d8188fbf6d017f1383e8dac1 --- /dev/null +++ b/0004-add-two-header-files-with-some-deleted-macros.patch @@ -0,0 +1,166 @@ +From d6e6184b4f10ef2cbdec09eae60350ced71e3de7 Mon Sep 17 00:00:00 2001 +From: Yang Yanchao +Date: Wed Nov 24 09:31:31 2021 +0800 +Subject: [PATCH 4/9] build extra lipthreadcond so + +For compatibility with glibc2.17, two header files are added with some +deleted macros. + +--- + nptl_2_17/compat_pthread_2_17.h | 61 +++++++++++++++++++++++++++ + nptl_2_17/old_macros_2_17.h | 75 +++++++++++++++++++++++++++++++++ + 2 files changed, 136 insertions(+) + create mode 100644 nptl_2_17/compat_pthread_2_17.h + create mode 100644 nptl_2_17/old_macros_2_17.h + +diff --git a/nptl_2_17/compat_pthread_2_17.h b/nptl_2_17/compat_pthread_2_17.h +new file mode 100644 +index 00000000..d13051ba +--- /dev/null ++++ b/nptl_2_17/compat_pthread_2_17.h +@@ -0,0 +1,61 @@ ++#ifndef _COMPAT_PTHREAD_2_17_H ++#define _COMPAT_PTHREAD_2_17_H 1 ++ ++#include ++#include ++ ++#ifdef __x86_64__ ++#define __PTHREAD_COMPAT_PADDING_MID ++#define __PTHREAD_COMPAT_PADDING_END ++#define __PTHREAD_MUTEX_LOCK_ELISION 1 ++# define __PTHREAD_MUTEX_NUSERS_AFTER_KIND 0 ++# define __PTHREAD_MUTEX_USE_UNION 0 ++//# define ENABLE_ELISION_SUPPORT 1 ++#else ++#define __PTHREAD_COMPAT_PADDING_MID ++#define __PTHREAD_COMPAT_PADDING_END ++#define __PTHREAD_MUTEX_LOCK_ELISION 0 ++#define __PTHREAD_MUTEX_NUSERS_AFTER_KIND 0 ++#define __PTHREAD_MUTEX_USE_UNION 0 ++#endif ++ ++#define CANCELSTATE_BIT 0 ++#define CANCELSTATE_BITMASK (0x01 << CANCELSTATE_BIT) ++ /* Bit set if asynchronous cancellation mode is selected. */ ++#define CANCELTYPE_BIT 1 ++#define CANCELTYPE_BITMASK (0x01 << CANCELTYPE_BIT) ++ /* Bit set if canceling has been initiated. */ ++#define CANCELING_BIT 2 ++#define CANCELING_BITMASK (0x01 << CANCELING_BIT) ++ /* Bit set if canceled. */ ++#define CANCELED_BIT 3 ++#define CANCELED_BITMASK (0x01 << CANCELED_BIT) ++ /* Bit set if thread is exiting. */ ++#define EXITING_BIT 4 ++#define EXITING_BITMASK (0x01 << EXITING_BIT) ++ /* Bit set if thread terminated and TCB is freed. */ ++#define TERMINATED_BIT 5 ++#define TERMINATED_BITMASK (0x01 << TERMINATED_BIT) ++ /* Bit set if thread is supposed to change XID. */ ++#define SETXID_BIT 6 ++#define SETXID_BITMASK (0x01 << SETXID_BIT) ++ /* Mask for the rest. Helps the compiler to optimize. */ ++#define CANCEL_RESTMASK 0xffffff80 ++ ++ ++#define CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS(value) \ ++ (((value) & (CANCELSTATE_BITMASK | CANCELTYPE_BITMASK | CANCELED_BITMASK \ ++ | EXITING_BITMASK | CANCEL_RESTMASK | TERMINATED_BITMASK)) \ ++ == (CANCELTYPE_BITMASK | CANCELED_BITMASK)) ++ ++# define INTERNAL_SYSCALL_DECL(err) do { } while (0) ++ ++/* ++ * __pause_nocancel delete by fbb4a3143724ef3f044a4f05351,add it ++ */ ++ ++__typeof (pause) __pause_nocancel; ++hidden_proto (__pause_nocancel) ++ ++#endif ++ +diff --git a/nptl_2_17/old_macros_2_17.h b/nptl_2_17/old_macros_2_17.h +new file mode 100644 +index 00000000..334b2ab1 +--- /dev/null ++++ b/nptl_2_17/old_macros_2_17.h +@@ -0,0 +1,75 @@ ++#ifndef _OLD_MACROS_2_17_H ++#define _OLD_MACROS_2_17_H 1 ++ ++/* ++ * Contains macros that have been defined in glibc2.34. ++ * Cancel the definition and use the old version. ++ * This header file needs to be included at the end. ++ */ ++#undef __lll_unlock ++#define __lll_unlock(futex, private) \ ++ ((void) \ ++ ({ \ ++ int *__futex = (futex); \ ++ int __private = (private); \ ++ int __oldval = atomic_exchange_rel (__futex, 0); \ ++ if (__glibc_unlikely (__oldval > 1)) \ ++ lll_futex_wake (__futex, 1, __private); \ ++ })) ++ ++#undef lll_unlock ++#define lll_unlock(futex, private) \ ++ __lll_unlock (&(futex), private) ++ ++extern int __lll_timedlock_wait (int *futex, const struct timespec *, ++ int private) attribute_hidden; ++ ++ ++/* As __lll_lock, but with a timeout. If the timeout occurs then return ++ ETIMEDOUT. If ABSTIME is invalid, return EINVAL. */ ++#define __lll_timedlock(futex, abstime, private) \ ++ ({ \ ++ int *__futex = (futex); \ ++ int __val = 0; \ ++ \ ++ if (__glibc_unlikely \ ++ (atomic_compare_and_exchange_bool_acq (__futex, 1, 0))) \ ++ __val = __lll_timedlock_wait (__futex, abstime, private); \ ++ __val; \ ++ }) ++#define lll_timedlock(futex, abstime, private) \ ++ __lll_timedlock (&(futex), abstime, private) ++ ++/* Verify whether the supplied clockid is supported by ++ lll_futex_clock_wait_bitset. */ ++#define lll_futex_supported_clockid(clockid) \ ++ ((clockid) == CLOCK_REALTIME || (clockid) == CLOCK_MONOTONIC) ++ ++/* The kernel currently only supports CLOCK_MONOTONIC or ++ CLOCK_REALTIME timeouts for FUTEX_WAIT_BITSET. We could attempt to ++ convert others here but currently do not. */ ++#define lll_futex_clock_wait_bitset(futexp, val, clockid, timeout, private) \ ++ ({ \ ++ long int __ret; \ ++ if (lll_futex_supported_clockid (clockid)) \ ++ { \ ++ const unsigned int clockbit = \ ++ (clockid == CLOCK_REALTIME) ? FUTEX_CLOCK_REALTIME : 0; \ ++ const int op = \ ++ __lll_private_flag (FUTEX_WAIT_BITSET | clockbit, private); \ ++ \ ++ __ret = lll_futex_syscall (6, futexp, op, val, \ ++ timeout, NULL /* Unused. */, \ ++ FUTEX_BITSET_MATCH_ANY); \ ++ } \ ++ else \ ++ __ret = -EINVAL; \ ++ __ret; \ ++ }) ++ ++# undef INTERNAL_VSYSCALL ++# define INTERNAL_VSYSCALL INTERNAL_SYSCALL ++# undef INLINE_VSYSCALL ++# define INLINE_VSYSCALL INLINE_SYSCALL ++ ++#endif +-- +2.30.0 + diff --git a/0005-add-pthread-functions_h.patch b/0005-add-pthread-functions_h.patch new file mode 100644 index 0000000000000000000000000000000000000000..f16914045c22f24cf8087a27fc2685227de9f703 --- /dev/null +++ b/0005-add-pthread-functions_h.patch @@ -0,0 +1,140 @@ +From 463dc947b4f9bc4137c9919ee72b896403926474 Mon Sep 17 00:00:00 2001 +From: Roland McGrath +Date: Thu Jun 12 13:48:47 2014 -0700 +Subject: [PATCH 5/9] build extra lipthreadcond so + +add pthread-functions.h which delete by 1d67cf9e8a0194588e66fb3b7afcbdc3bf836a + +--- + nptl_2_17/pthread-functions_2_17.h | 119 +++++++++++++++++++++++++++++ + 1 file changed, 119 insertions(+) + create mode 100644 nptl_2_17/pthread-functions_2_17.h + +diff --git a/nptl_2_17/pthread-functions_2_17.h b/nptl_2_17/pthread-functions_2_17.h +new file mode 100644 +index 00000000..07ca8e7e +--- /dev/null ++++ b/nptl_2_17/pthread-functions_2_17.h +@@ -0,0 +1,119 @@ ++/* Copyright (C) 2003-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Ulrich Drepper , 2003. ++ ++ 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 ++ . */ ++ ++#ifndef _PTHREAD_FUNCTIONS_H ++#define _PTHREAD_FUNCTIONS_H 1 ++ ++#include ++#include ++#include ++#include ++ ++struct xid_command; ++ ++/* Data type shared with libc. The libc uses it to pass on calls to ++ the thread functions. */ ++struct pthread_functions ++{ ++ int (*ptr_pthread_attr_destroy) (pthread_attr_t *); ++ int (*ptr___pthread_attr_init_2_0) (pthread_attr_t *); ++ int (*ptr___pthread_attr_init_2_1) (pthread_attr_t *); ++ int (*ptr_pthread_attr_getdetachstate) (const pthread_attr_t *, int *); ++ int (*ptr_pthread_attr_setdetachstate) (pthread_attr_t *, int); ++ int (*ptr_pthread_attr_getinheritsched) (const pthread_attr_t *, int *); ++ int (*ptr_pthread_attr_setinheritsched) (pthread_attr_t *, int); ++ int (*ptr_pthread_attr_getschedparam) (const pthread_attr_t *, ++ struct sched_param *); ++ int (*ptr_pthread_attr_setschedparam) (pthread_attr_t *, ++ const struct sched_param *); ++ int (*ptr_pthread_attr_getschedpolicy) (const pthread_attr_t *, int *); ++ int (*ptr_pthread_attr_setschedpolicy) (pthread_attr_t *, int); ++ int (*ptr_pthread_attr_getscope) (const pthread_attr_t *, int *); ++ int (*ptr_pthread_attr_setscope) (pthread_attr_t *, int); ++ int (*ptr_pthread_condattr_destroy) (pthread_condattr_t *); ++ int (*ptr_pthread_condattr_init) (pthread_condattr_t *); ++ int (*ptr___pthread_cond_broadcast) (pthread_cond_t *); ++ int (*ptr___pthread_cond_destroy) (pthread_cond_t *); ++ int (*ptr___pthread_cond_init) (pthread_cond_t *, ++ const pthread_condattr_t *); ++ int (*ptr___pthread_cond_signal) (pthread_cond_t *); ++ int (*ptr___pthread_cond_wait) (pthread_cond_t *, pthread_mutex_t *); ++ int (*ptr___pthread_cond_timedwait) (pthread_cond_t *, pthread_mutex_t *, ++ const struct timespec *); ++ int (*ptr___pthread_cond_clockwait) (pthread_cond_t *, ++ pthread_mutex_t *, ++ clockid_t, ++ const struct timespec *); ++ int (*ptr___pthread_cond_broadcast_2_0) (pthread_cond_2_0_t *); ++ int (*ptr___pthread_cond_destroy_2_0) (pthread_cond_2_0_t *); ++ int (*ptr___pthread_cond_init_2_0) (pthread_cond_2_0_t *, ++ const pthread_condattr_t *); ++ int (*ptr___pthread_cond_signal_2_0) (pthread_cond_2_0_t *); ++ int (*ptr___pthread_cond_wait_2_0) (pthread_cond_2_0_t *, pthread_mutex_t *); ++ int (*ptr___pthread_cond_timedwait_2_0) (pthread_cond_2_0_t *, ++ pthread_mutex_t *, ++ const struct timespec *); ++ int (*ptr_pthread_equal) (pthread_t, pthread_t); ++ void (*ptr___pthread_exit) (void *) __attribute__ ((__noreturn__)); ++ int (*ptr_pthread_getschedparam) (pthread_t, int *, struct sched_param *); ++ int (*ptr_pthread_setschedparam) (pthread_t, int, ++ const struct sched_param *); ++ int (*ptr_pthread_mutex_destroy) (pthread_mutex_t *); ++ int (*ptr_pthread_mutex_init) (pthread_mutex_t *, ++ const pthread_mutexattr_t *); ++ int (*ptr_pthread_mutex_lock) (pthread_mutex_t *); ++ int (*ptr_pthread_mutex_unlock) (pthread_mutex_t *); ++ int (*ptr___pthread_setcancelstate) (int, int *); ++ int (*ptr_pthread_setcanceltype) (int, int *); ++ void (*ptr___pthread_cleanup_upto) (__jmp_buf, char *); ++ int (*ptr___pthread_once) (pthread_once_t *, void (*) (void)); ++ int (*ptr___pthread_rwlock_rdlock) (pthread_rwlock_t *); ++ int (*ptr___pthread_rwlock_wrlock) (pthread_rwlock_t *); ++ int (*ptr___pthread_rwlock_unlock) (pthread_rwlock_t *); ++ int (*ptr___pthread_key_create) (pthread_key_t *, void (*) (void *)); ++ void *(*ptr___pthread_getspecific) (pthread_key_t); ++ int (*ptr___pthread_setspecific) (pthread_key_t, const void *); ++ void (*ptr__pthread_cleanup_push_defer) (struct _pthread_cleanup_buffer *, ++ void (*) (void *), void *); ++ void (*ptr__pthread_cleanup_pop_restore) (struct _pthread_cleanup_buffer *, ++ int); ++#define HAVE_PTR_NTHREADS ++ unsigned int *ptr_nthreads; ++ void (*ptr___pthread_unwind) (__pthread_unwind_buf_t *) ++ __attribute ((noreturn)) __cleanup_fct_attribute; ++ void (*ptr__nptl_deallocate_tsd) (void); ++ int (*ptr__nptl_setxid) (struct xid_command *); ++ void (*ptr_set_robust) (struct pthread *); ++}; ++ ++/* Variable in libc.so. */ ++extern struct pthread_functions __libc_pthread_functions attribute_hidden; ++extern int __libc_pthread_functions_init attribute_hidden; ++ ++#ifdef PTR_DEMANGLE ++# define PTHFCT_CALL(fct, params) \ ++ ({ __typeof (__libc_pthread_functions.fct) __p; \ ++ __p = __libc_pthread_functions.fct; \ ++ PTR_DEMANGLE (__p); \ ++ __p params; }) ++#else ++# define PTHFCT_CALL(fct, params) \ ++ __libc_pthread_functions.fct params ++#endif ++ ++#endif /* pthread-functions.h */ +-- +2.30.0 + diff --git a/0006-add-elsion-function-which-moved-to-libc-in-glibc-2.34.patch b/0006-add-elsion-function-which-moved-to-libc-in-glibc-2.34.patch new file mode 100644 index 0000000000000000000000000000000000000000..e60fc086d8944308bb3c1790cccd137604087f07 --- /dev/null +++ b/0006-add-elsion-function-which-moved-to-libc-in-glibc-2.34.patch @@ -0,0 +1,587 @@ +From 1cdbe579482c07e9f4bb3baa4864da2d3e7eb837 Mon Sep 17 00:00:00 2001 +From: Andi Kleen +Date: Sat, 10 Nov 2012 00:51:26 -0800i +Subject: [PATCH 6/9] build extra lipthreadcond so + +add elsion functions which moved to libc in glibc-2.34. +Some attributes are changed and cannot be directly referenced. + + +--- + nptl_2_17/lll_timedlock_wait_2_17.c | 59 +++++++++++++++++++++++++++++ + nptl_2_17/elision-conf_2_17.c | 138 +++++++++++++++++++++++++++++++ + nptl_2_17/elision-lock_2_17.c | 107 ++++++++++++++++++++++++ + nptl_2_17/elision-timed_2_17.c | 27 ++++++ + nptl_2_17/elision-trylock_2_17.c | 75 +++++++++++++++++ + nptl_2_17/elision-unlock_2_17.c | 34 ++++++++ + nptl_2_17/hle_2_17.h | 75 +++++++++++++++++ + 6 files changed, 515 + insertions(+) + create mode 100644 nptl_2_17/lll_timedlock_wait_2_17.c + create mode 100644 nptl_2_17/elision-conf_2_17.c + create mode 100644 nptl_2_17/elision-lock_2_17.c + create mode 100644 nptl_2_17/elision-timed_2_17.c + create mode 100644 nptl_2_17/elision-trylock_2_17.c + create mode 100644 nptl_2_17/elision-unlock_2_17.c + create mode 100644 nptl_2_17/hle_2_17.h + +diff --git a/nptl_2_17/lll_timedlock_wait_2_17.c b/nptl_2_17/lll_timedlock_wait_2_17.c +new file mode 100644 +index 00000000..91bf9637 +--- /dev/null ++++ b/nptl_2_17/lll_timedlock_wait_2_17.c +@@ -0,0 +1,59 @@ ++/* Timed low level locking for pthread library. Generic futex-using version. ++ Copyright (C) 2003-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Paul Mackerras , 2003. ++ ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++ ++int ++__lll_timedlock_wait (int *futex, const struct timespec *abstime, int private) ++{ ++ /* Reject invalid timeouts. */ ++ if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) ++ return EINVAL; ++ ++ /* Try locking. */ ++ while (atomic_exchange_acq (futex, 2) != 0) ++ { ++ struct timeval tv; ++ ++ /* Get the current time. */ ++ (void) __gettimeofday (&tv, NULL); ++ ++ /* Compute relative timeout. */ ++ struct timespec rt; ++ rt.tv_sec = abstime->tv_sec - tv.tv_sec; ++ rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; ++ if (rt.tv_nsec < 0) ++ { ++ rt.tv_nsec += 1000000000; ++ --rt.tv_sec; ++ } ++ ++ if (rt.tv_sec < 0) ++ return ETIMEDOUT; ++ ++ /* If *futex == 2, wait until woken or timeout. */ ++ lll_futex_timed_wait (futex, 2, &rt, private); ++ } ++ ++ return 0; ++} +diff --git a/nptl_2_17/elision-conf_2_17.c b/nptl_2_17/elision-conf_2_17.c +new file mode 100644 +index 00000000..22af2944 +--- /dev/null ++++ b/nptl_2_17/elision-conf_2_17.c +@@ -0,0 +1,138 @@ ++/* elision-conf.c: Lock elision tunable parameters. ++ Copyright (C) 2013-2018 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 ++ . */ ++ ++#include "config.h" ++#include ++#include ++#include ++#include ++ ++#if HAVE_TUNABLES ++# define TUNABLE_NAMESPACE elision ++#endif ++#include ++ ++/* Reasonable initial tuning values, may be revised in the future. ++ This is a conservative initial value. */ ++ ++struct elision_config __elision_aconf = ++ { ++ /* How often to not attempt to use elision if a transaction aborted ++ because the lock is already acquired. Expressed in number of lock ++ acquisition attempts. */ ++ .skip_lock_busy = 3, ++ /* How often to not attempt to use elision if a transaction aborted due ++ to reasons other than other threads' memory accesses. Expressed in ++ number of lock acquisition attempts. */ ++ .skip_lock_internal_abort = 3, ++ /* How often we retry using elision if there is chance for the transaction ++ to finish execution (e.g., it wasn't aborted due to the lock being ++ already acquired. */ ++ .retry_try_xbegin = 3, ++ /* Same as SKIP_LOCK_INTERNAL_ABORT but for trylock. */ ++ .skip_trylock_internal_abort = 3, ++ }; ++ ++/* Force elision for all new locks. This is used to decide whether existing ++ DEFAULT locks should be automatically upgraded to elision in ++ pthread_mutex_lock(). Disabled for suid programs. Only used when elision ++ is available. */ ++ ++int __pthread_force_elision attribute_hidden = 0; ++ ++#if HAVE_TUNABLES ++static inline void ++__always_inline ++do_set_elision_enable (int32_t elision_enable) ++{ ++ /* Enable elision if it's avaliable in hardware. It's not necessary to check ++ if __libc_enable_secure isn't enabled since elision_enable will be set ++ according to the default, which is disabled. */ ++ if (elision_enable == 1) ++ __pthread_force_elision = HAS_CPU_FEATURE (RTM) ? 1 : 0; ++} ++ ++/* The pthread->elision_enable tunable is 0 or 1 indicating that elision ++ should be disabled or enabled respectively. The feature will only be used ++ if it's supported by the hardware. */ ++ ++void ++TUNABLE_CALLBACK (set_elision_enable) (tunable_val_t *valp) ++{ ++ int32_t elision_enable = (int32_t) valp->numval; ++ do_set_elision_enable (elision_enable); ++} ++ ++#define TUNABLE_CALLBACK_FNDECL(__name, __type) \ ++static inline void \ ++__always_inline \ ++do_set_elision_ ## __name (__type value) \ ++{ \ ++ __elision_aconf.__name = value; \ ++} \ ++void \ ++TUNABLE_CALLBACK (set_elision_ ## __name) (tunable_val_t *valp) \ ++{ \ ++ __type value = (__type) (valp)->numval; \ ++ do_set_elision_ ## __name (value); \ ++} ++ ++TUNABLE_CALLBACK_FNDECL (skip_lock_busy, int32_t); ++TUNABLE_CALLBACK_FNDECL (skip_lock_internal_abort, int32_t); ++TUNABLE_CALLBACK_FNDECL (retry_try_xbegin, int32_t); ++TUNABLE_CALLBACK_FNDECL (skip_trylock_internal_abort, int32_t); ++#endif ++ ++/* Initialize elision. */ ++ ++static void ++elision_init (int argc __attribute__ ((unused)), ++ char **argv __attribute__ ((unused)), ++ char **environ) ++{ ++#if HAVE_TUNABLES ++ /* Elision depends on tunables and must be explicitly turned on by setting ++ the appropriate tunable on a supported platform. */ ++ ++ TUNABLE_GET (enable, int32_t, ++ TUNABLE_CALLBACK (set_elision_enable)); ++ TUNABLE_GET (skip_lock_busy, int32_t, ++ TUNABLE_CALLBACK (set_elision_skip_lock_busy)); ++ TUNABLE_GET (skip_lock_internal_abort, int32_t, ++ TUNABLE_CALLBACK (set_elision_skip_lock_internal_abort)); ++ TUNABLE_GET (tries, int32_t, ++ TUNABLE_CALLBACK (set_elision_retry_try_xbegin)); ++ TUNABLE_GET (skip_trylock_internal_abort, int32_t, ++ TUNABLE_CALLBACK (set_elision_skip_trylock_internal_abort)); ++#endif ++ ++ if (!__pthread_force_elision) ++ __elision_aconf.retry_try_xbegin = 0; /* Disable elision on rwlocks. */ ++} ++ ++#ifdef SHARED ++# define INIT_SECTION ".init_array" ++#else ++# define INIT_SECTION ".preinit_array" ++#endif ++ ++void (*const __pthread_init_array []) (int, char **, char **) ++ __attribute__ ((section (INIT_SECTION), aligned (sizeof (void *)))) = ++{ ++ &elision_init ++}; +diff --git a/nptl_2_17/elision-lock_2_17.c b/nptl_2_17/elision-lock_2_17.c +new file mode 100644 +index 00000000..e6dbbc21 +--- /dev/null ++++ b/nptl_2_17/elision-lock_2_17.c +@@ -0,0 +1,107 @@ ++/* elision-lock.c: Elided pthread mutex lock. ++ Copyright (C) 2011-2018 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 ++ . */ ++ ++#include ++#include "pthreadP_2_17.h" ++#include "lowlevellock.h" ++#include "hle_2_17.h" ++#include ++ ++#if !defined(LLL_LOCK) && !defined(EXTRAARG) ++/* Make sure the configuration code is always linked in for static ++ libraries. */ ++#include "elision-conf_2_17.c" ++#endif ++ ++#ifndef EXTRAARG ++#define EXTRAARG ++#endif ++#ifndef LLL_LOCK ++#define LLL_LOCK(a,b) lll_lock(a,b), 0 ++#endif ++ ++#define aconf __elision_aconf ++ ++/* Adaptive lock using transactions. ++ By default the lock region is run as a transaction, and when it ++ aborts or the lock is busy the lock adapts itself. */ ++ ++int ++__lll_lock_elision (int *futex, short *adapt_count, EXTRAARG int private) ++{ ++ /* adapt_count can be accessed concurrently; these accesses can be both ++ inside of transactions (if critical sections are nested and the outer ++ critical section uses lock elision) and outside of transactions. Thus, ++ we need to use atomic accesses to avoid data races. However, the ++ value of adapt_count is just a hint, so relaxed MO accesses are ++ sufficient. */ ++ if (atomic_load_relaxed (adapt_count) <= 0) ++ { ++ unsigned status; ++ int try_xbegin; ++ ++ for (try_xbegin = aconf.retry_try_xbegin; ++ try_xbegin > 0; ++ try_xbegin--) ++ { ++ if ((status = _xbegin()) == _XBEGIN_STARTED) ++ { ++ if (*futex == 0) ++ return 0; ++ ++ /* Lock was busy. Fall back to normal locking. ++ Could also _xend here but xabort with 0xff code ++ is more visible in the profiler. */ ++ _xabort (_ABORT_LOCK_BUSY); ++ } ++ ++ if (!(status & _XABORT_RETRY)) ++ { ++ if ((status & _XABORT_EXPLICIT) ++ && _XABORT_CODE (status) == _ABORT_LOCK_BUSY) ++ { ++ /* Right now we skip here. Better would be to wait a bit ++ and retry. This likely needs some spinning. See ++ above for why relaxed MO is sufficient. */ ++ if (atomic_load_relaxed (adapt_count) ++ != aconf.skip_lock_busy) ++ atomic_store_relaxed (adapt_count, aconf.skip_lock_busy); ++ } ++ /* Internal abort. There is no chance for retry. ++ Use the normal locking and next time use lock. ++ Be careful to avoid writing to the lock. See above for why ++ relaxed MO is sufficient. */ ++ else if (atomic_load_relaxed (adapt_count) ++ != aconf.skip_lock_internal_abort) ++ atomic_store_relaxed (adapt_count, ++ aconf.skip_lock_internal_abort); ++ break; ++ } ++ } ++ } ++ else ++ { ++ /* Use a normal lock until the threshold counter runs out. ++ Lost updates possible. */ ++ atomic_store_relaxed (adapt_count, ++ atomic_load_relaxed (adapt_count) - 1); ++ } ++ ++ /* Use a normal lock here. */ ++ return LLL_LOCK ((*futex), private); ++} +diff --git a/nptl_2_17/elision-timed_2_17.c b/nptl_2_17/elision-timed_2_17.c +new file mode 100644 +index 00000000..5050f2d1 +--- /dev/null ++++ b/nptl_2_17/elision-timed_2_17.c +@@ -0,0 +1,27 @@ ++/* elision-timed.c: Lock elision timed lock. ++ Copyright (C) 2013-2018 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 ++ . */ ++ ++#include ++#include ++#include "lowlevellock.h" ++#include ++#define __lll_lock_elision __lll_timedlock_elision ++#define EXTRAARG const struct timespec *t, ++#undef LLL_LOCK ++#define LLL_LOCK(a, b) lll_timedlock(a, t, b) ++#include "elision-lock_2_17.c" +diff --git a/nptl_2_17/elision-trylock_2_17.c b/nptl_2_17/elision-trylock_2_17.c +new file mode 100644 +index 00000000..70d8f8b9 +--- /dev/null ++++ b/nptl_2_17/elision-trylock_2_17.c +@@ -0,0 +1,75 @@ ++/* elision-trylock.c: Lock eliding trylock for pthreads. ++ Copyright (C) 2013-2018 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 ++ . */ ++ ++#include ++ ++#include ++#include "hle_2_17.h" ++#include ++ ++#define aconf __elision_aconf ++ ++/* Try to elide a futex trylock. FUTEX is the futex variable. ADAPT_COUNT is ++ the adaptation counter in the mutex. */ ++ ++int ++__lll_trylock_elision (int *futex, short *adapt_count) ++{ ++ /* Implement POSIX semantics by forbiding nesting ++ trylock. Sorry. After the abort the code is re-executed ++ non transactional and if the lock was already locked ++ return an error. */ ++ _xabort (_ABORT_NESTED_TRYLOCK); ++ ++ /* Only try a transaction if it's worth it. See __lll_lock_elision for ++ why we need atomic accesses. Relaxed MO is sufficient because this is ++ just a hint. */ ++ if (atomic_load_relaxed (adapt_count) <= 0) ++ { ++ unsigned status; ++ ++ if ((status = _xbegin()) == _XBEGIN_STARTED) ++ { ++ if (*futex == 0) ++ return 0; ++ ++ /* Lock was busy. Fall back to normal locking. ++ Could also _xend here but xabort with 0xff code ++ is more visible in the profiler. */ ++ _xabort (_ABORT_LOCK_BUSY); ++ } ++ ++ if (!(status & _XABORT_RETRY)) ++ { ++ /* Internal abort. No chance for retry. For future ++ locks don't try speculation for some time. See above for MO. */ ++ if (atomic_load_relaxed (adapt_count) ++ != aconf.skip_lock_internal_abort) ++ atomic_store_relaxed (adapt_count, aconf.skip_lock_internal_abort); ++ } ++ /* Could do some retries here. */ ++ } ++ else ++ { ++ /* Lost updates are possible but harmless (see above). */ ++ atomic_store_relaxed (adapt_count, ++ atomic_load_relaxed (adapt_count) - 1); ++ } ++ ++ return lll_trylock (*futex); ++} +diff --git a/nptl_2_17/elision-unlock_2_17.c b/nptl_2_17/elision-unlock_2_17.c +new file mode 100644 +index 00000000..b5d38c5f +--- /dev/null ++++ b/nptl_2_17/elision-unlock_2_17.c +@@ -0,0 +1,34 @@ ++/* elision-unlock.c: Commit an elided pthread lock. ++ Copyright (C) 2013-2018 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 ++ . */ ++ ++#include "pthreadP_2_17.h" ++#include "lowlevellock.h" ++#include "hle_2_17.h" ++#include ++ ++int ++__lll_unlock_elision(int *lock, int private) ++{ ++ /* When the lock was free we're in a transaction. ++ When you crash here you unlocked a free lock. */ ++ if (*lock == 0) ++ _xend(); ++ else ++ lll_unlock ((*lock), private); ++ return 0; ++} +diff --git a/nptl_2_17/hle_2_17.h b/nptl_2_17/hle_2_17.h +new file mode 100644 +index 00000000..4a7b9e3b +--- /dev/null ++++ b/nptl_2_17/hle_2_17.h +@@ -0,0 +1,75 @@ ++/* Shared RTM header. Emulate TSX intrinsics for compilers and assemblers ++ that do not support the intrinsics and instructions yet. */ ++#ifndef _HLE_H ++#define _HLE_H 1 ++ ++#ifdef __ASSEMBLER__ ++ ++.macro XBEGIN target ++ .byte 0xc7,0xf8 ++ .long \target-1f ++1: ++.endm ++ ++.macro XEND ++ .byte 0x0f,0x01,0xd5 ++.endm ++ ++.macro XABORT code ++ .byte 0xc6,0xf8,\code ++.endm ++ ++.macro XTEST ++ .byte 0x0f,0x01,0xd6 ++.endm ++ ++#endif ++ ++/* Official RTM intrinsics interface matching gcc/icc, but works ++ on older gcc compatible compilers and binutils. ++ We should somehow detect if the compiler supports it, because ++ it may be able to generate slightly better code. */ ++ ++#define _XBEGIN_STARTED (~0u) ++#define _XABORT_EXPLICIT (1 << 0) ++#define _XABORT_RETRY (1 << 1) ++#define _XABORT_CONFLICT (1 << 2) ++#define _XABORT_CAPACITY (1 << 3) ++#define _XABORT_DEBUG (1 << 4) ++#define _XABORT_NESTED (1 << 5) ++#define _XABORT_CODE(x) (((x) >> 24) & 0xff) ++ ++#define _ABORT_LOCK_BUSY 0xff ++#define _ABORT_LOCK_IS_LOCKED 0xfe ++#define _ABORT_NESTED_TRYLOCK 0xfd ++ ++#ifndef __ASSEMBLER__ ++ ++#define __force_inline __attribute__((__always_inline__)) inline ++ ++static __force_inline int _xbegin(void) ++{ ++ int ret = _XBEGIN_STARTED; ++ asm volatile (".byte 0xc7,0xf8 ; .long 0" : "+a" (ret) :: "memory"); ++ return ret; ++} ++ ++static __force_inline void _xend(void) ++{ ++ asm volatile (".byte 0x0f,0x01,0xd5" ::: "memory"); ++} ++ ++static __force_inline void _xabort(const unsigned int status) ++{ ++ asm volatile (".byte 0xc6,0xf8,%P0" :: "i" (status) : "memory"); ++} ++ ++static __force_inline int _xtest(void) ++{ ++ unsigned char out; ++ asm volatile (".byte 0x0f,0x01,0xd6 ; setnz %0" : "=r" (out) :: "memory"); ++ return out; ++} ++ ++#endif ++#endif +-- +2.30.0 + diff --git a/0007-add-lowlevellock_2_17_c.patch b/0007-add-lowlevellock_2_17_c.patch new file mode 100644 index 0000000000000000000000000000000000000000..b516e7732497302a0977e421e394f403c5df95cd --- /dev/null +++ b/0007-add-lowlevellock_2_17_c.patch @@ -0,0 +1,68 @@ +From 3df6f22e5fde470a6e0242e582e58919493bdd54 Mon Sep 17 00:00:00 2001 +From: Roland McGrath +Date: Tue, 15 Jul 2014 15:23:06 -0700 +Subject: [PATCH 7/9] build extra lipthreadcond so + +since 78fe624d44b8f6489b2d0de9bfdc09290a719a7, lowlevellock.c depends futex-internal.h which uses the private symbol __GI___libc_fatal of glibc. +We can't reference it in libpthread-2.17.so. Therefore, recompile in libphtread-2.17.so + +--- + nptl_2_17/lowlevellock_2_17.c | 46 ++++++++++++++++++++++ + 2 files changed, 46 insertions(+) + create mode 100644 nptl_2_17/lowlevellock_2_17.c + +diff --git a/nptl_2_17/lowlevellock_2_17.c b/nptl_2_17/lowlevellock_2_17.c +new file mode 100644 +index 00000000..bf1ca6b9 +--- /dev/null ++++ b/nptl_2_17/lowlevellock_2_17.c +@@ -0,0 +1,46 @@ ++/* low level locking for pthread library. Generic futex-using version. ++ Copyright (C) 2003-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Paul Mackerras , 2003. ++ ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++void ++__lll_lock_wait_private (int *futex) ++{ ++ if (*futex == 2) ++ lll_futex_wait (futex, 2, LLL_PRIVATE); /* Wait if *futex == 2. */ ++ ++ while (atomic_exchange_acq (futex, 2) != 0) ++ lll_futex_wait (futex, 2, LLL_PRIVATE); /* Wait if *futex == 2. */ ++} ++ ++ ++/* This function doesn't get included in libc. */ ++void ++__lll_lock_wait (int *futex, int private) ++{ ++ if (*futex == 2) ++ lll_futex_wait (futex, 2, private); /* Wait if *futex == 2. */ ++ ++ while (atomic_exchange_acq (futex, 2) != 0) ++ lll_futex_wait (futex, 2, private); /* Wait if *futex == 2. */ ++} +-- +2.30.0 + diff --git a/0008-add-pause_nocancel_2_17.patch b/0008-add-pause_nocancel_2_17.patch new file mode 100644 index 0000000000000000000000000000000000000000..8d7ec88835c2340e4ae1ef9750dc1fe484a317c3 --- /dev/null +++ b/0008-add-pause_nocancel_2_17.patch @@ -0,0 +1,56 @@ +From 329ea513b451ae8322aa7a24ed84da13992af2dd Mon Sep 17 00:00:00 2001 +From: Zack Weinberg +Date: Tue, 3 Apr 2018 18:26:44 -0400 +Subject: [PATCH 8/9] build extra lipthreadcond so + +since bb4a3143724ef3f044a4f05351fe041300ee382, Remove pause and nanosleep not cancel wrappers +To build libtphread-2.17.so, we added it back. + +--- + nptl_2_17/pause_nocancel_2_17.c | 34 +++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + create mode 100644 nptl_2_17/pause_nocancel_2_17.c + +diff --git a/nptl_2_17/pause_nocancel_2_17.c b/nptl_2_17/pause_nocancel_2_17.c +new file mode 100644 +index 00000000..ab8e78d2 +--- /dev/null ++++ b/nptl_2_17/pause_nocancel_2_17.c +@@ -0,0 +1,34 @@ ++/* Linux pause syscall implementation -- non-cancellable. ++ Copyright (C) 2018 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++int ++__pause_nocancel (void) ++{ ++#ifdef __NR_pause ++ return INLINE_SYSCALL_CALL (pause); ++#else ++ return INLINE_SYSCALL_CALL (ppoll, NULL, 0, NULL, NULL); ++#endif ++} ++hidden_def (__pause_nocancel) +-- +2.30.0 + diff --git a/0009-add-unwind-with-longjmp.patch b/0009-add-unwind-with-longjmp.patch new file mode 100644 index 0000000000000000000000000000000000000000..cfe1ecb1779c933a76e6a6fa1768c5f7b2478063 --- /dev/null +++ b/0009-add-unwind-with-longjmp.patch @@ -0,0 +1,161 @@ +From 09d65ff393e9183eecba1e5cb877e95dbdd3d4a4 Mon Sep 17 00:00:00 2001 +From: Ulrich Drepper +Date: Sat, 12 Apr 2003 00:58:26 +0000 +Subject: [PATCH 9/9] build extra lipthreadcond so + +since 6253bacdc00de132dec452ff7c6ce3ba7fa23d81, __libc_longjmp became a +private interface.We can't quote directly. +Change it to longjmp + +--- + nptl_2_17/unwind_2_17.c | 138 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 138 insertions(+) + create mode 100644 nptl_2_17/unwind_2_17.c + +diff --git a/nptl_2_17/unwind_2_17.c b/nptl_2_17/unwind_2_17.c +new file mode 100644 +index 00000000..ada8f74d +--- /dev/null ++++ b/nptl_2_17/unwind_2_17.c +@@ -0,0 +1,138 @@ ++/* Copyright (C) 2003-2016 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Ulrich Drepper ++ and Richard Henderson , 2003. ++ ++ 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 ++ . */ ++ ++#include "pthreadP_2_17.h" ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef _STACK_GROWS_DOWN ++# define FRAME_LEFT(frame, other, adj) \ ++ ((uintptr_t) frame - adj >= (uintptr_t) other - adj) ++#elif _STACK_GROWS_UP ++# define FRAME_LEFT(frame, other, adj) \ ++ ((uintptr_t) frame - adj <= (uintptr_t) other - adj) ++#else ++# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP" ++#endif ++ ++static _Unwind_Reason_Code ++unwind_stop (int version, _Unwind_Action actions, ++ _Unwind_Exception_Class exc_class, ++ struct _Unwind_Exception *exc_obj, ++ struct _Unwind_Context *context, void *stop_parameter) ++{ ++ struct pthread_unwind_buf *buf = stop_parameter; ++ struct pthread *self = THREAD_SELF; ++ struct _pthread_cleanup_buffer *curp = THREAD_GETMEM (self, cleanup); ++ int do_longjump = 0; ++ ++ /* Adjust all pointers used in comparisons, so that top of thread's ++ stack is at the top of address space. Without that, things break ++ if stack is allocated above the main stack. */ ++ uintptr_t adj = (uintptr_t) self->stackblock + self->stackblock_size; ++ ++ /* Do longjmp if we're at "end of stack", aka "end of unwind data". ++ We assume there are only C frame without unwind data in between ++ here and the jmp_buf target. Otherwise simply note that the CFA ++ of a function is NOT within it's stack frame; it's the SP of the ++ previous frame. */ ++ if ((actions & _UA_END_OF_STACK) ++ || ! _JMPBUF_CFA_UNWINDS_ADJ (buf->cancel_jmp_buf[0].jmp_buf, context, ++ adj)) ++ do_longjump = 1; ++ ++ if (__glibc_unlikely (curp != NULL)) ++ { ++ /* Handle the compatibility stuff. Execute all handlers ++ registered with the old method which would be unwound by this ++ step. */ ++ struct _pthread_cleanup_buffer *oldp = buf->priv.data.cleanup; ++ void *cfa = (void *) (_Unwind_Ptr) _Unwind_GetCFA (context); ++ ++ if (curp != oldp && (do_longjump || FRAME_LEFT (cfa, curp, adj))) ++ { ++ do ++ { ++ /* Pointer to the next element. */ ++ struct _pthread_cleanup_buffer *nextp = curp->__prev; ++ ++ /* Call the handler. */ ++ curp->__routine (curp->__arg); ++ ++ /* To the next. */ ++ curp = nextp; ++ } ++ while (curp != oldp ++ && (do_longjump || FRAME_LEFT (cfa, curp, adj))); ++ ++ /* Mark the current element as handled. */ ++ THREAD_SETMEM (self, cleanup, curp); ++ } ++ } ++ ++ if (do_longjump) ++ longjmp ((struct __jmp_buf_tag *) buf->cancel_jmp_buf, 1); ++ ++ return _URC_NO_REASON; ++} ++ ++ ++static void ++unwind_cleanup (_Unwind_Reason_Code reason, struct _Unwind_Exception *exc) ++{ ++ /* When we get here a C++ catch block didn't rethrow the object. We ++ cannot handle this case and therefore abort. */ ++ __libc_fatal ("FATAL: exception not rethrown\n"); ++} ++ ++ ++void ++__cleanup_fct_attribute __attribute ((noreturn)) ++__pthread_unwind (__pthread_unwind_buf_t *buf) ++{ ++ struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf; ++ struct pthread *self = THREAD_SELF; ++ ++ /* This is not a catchable exception, so don't provide any details about ++ the exception type. We do need to initialize the field though. */ ++ THREAD_SETMEM (self, exc.exception_class, 0); ++ THREAD_SETMEM (self, exc.exception_cleanup, &unwind_cleanup); ++ ++ _Unwind_ForcedUnwind (&self->exc, unwind_stop, ibuf); ++ /* NOTREACHED */ ++ ++ /* We better do not get here. */ ++ abort (); ++} ++hidden_def (__pthread_unwind) ++ ++ ++void ++__cleanup_fct_attribute __attribute ((noreturn)) ++__pthread_unwind_next (__pthread_unwind_buf_t *buf) ++{ ++ struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf; ++ ++ __pthread_unwind ((__pthread_unwind_buf_t *) ibuf->priv.data.prev); ++} ++hidden_def (__pthread_unwind_next) +-- +2.30.0 + diff --git a/1-5-AArch64-Improve-A64FX-memset-for-small-sizes.patch b/1-5-AArch64-Improve-A64FX-memset-for-small-sizes.patch new file mode 100644 index 0000000000000000000000000000000000000000..2db004518382383d0814b1acc240f24ba6fcd6f2 --- /dev/null +++ b/1-5-AArch64-Improve-A64FX-memset-for-small-sizes.patch @@ -0,0 +1,136 @@ +From 07b427296b8d59f439144029d9a948f6c1ce0a31 Mon Sep 17 00:00:00 2001 +From: Wilco Dijkstra +Date: Tue, 10 Aug 2021 13:30:27 +0100 +Subject: [PATCH] [1/5] AArch64: Improve A64FX memset for small sizes + +Improve performance of small memsets by reducing instruction counts and +improving code alignment. Bench-memset shows 35-45% performance gain for +small sizes. + +Reviewed-by: Naohiro Tamura +--- + sysdeps/aarch64/multiarch/memset_a64fx.S | 96 ++++++++++++-------------------- + 1 file changed, 36 insertions(+), 60 deletions(-) + +diff --git a/sysdeps/aarch64/multiarch/memset_a64fx.S b/sysdeps/aarch64/multiarch/memset_a64fx.S +index ce54e54..cf3d402 100644 +--- a/sysdeps/aarch64/multiarch/memset_a64fx.S ++++ b/sysdeps/aarch64/multiarch/memset_a64fx.S +@@ -51,78 +51,54 @@ + .endm + + .macro st1b_unroll first=0, last=7 +- st1b z0.b, p0, [dst, #\first, mul vl] ++ st1b z0.b, p0, [dst, \first, mul vl] + .if \last-\first + st1b_unroll "(\first+1)", \last + .endif + .endm + +- .macro shortcut_for_small_size exit +- // if rest <= vector_length * 2 +- whilelo p0.b, xzr, count +- whilelo p1.b, vector_length, count +- b.last 1f +- st1b z0.b, p0, [dstin, #0, mul vl] +- st1b z0.b, p1, [dstin, #1, mul vl] +- ret +-1: // if rest > vector_length * 8 +- cmp count, vector_length, lsl 3 // vector_length * 8 +- b.hi \exit +- // if rest <= vector_length * 4 +- lsl tmp1, vector_length, 1 // vector_length * 2 +- whilelo p2.b, tmp1, count +- incb tmp1 +- whilelo p3.b, tmp1, count +- b.last 1f +- st1b z0.b, p0, [dstin, #0, mul vl] +- st1b z0.b, p1, [dstin, #1, mul vl] +- st1b z0.b, p2, [dstin, #2, mul vl] +- st1b z0.b, p3, [dstin, #3, mul vl] +- ret +-1: // if rest <= vector_length * 8 +- lsl tmp1, vector_length, 2 // vector_length * 4 +- whilelo p4.b, tmp1, count +- incb tmp1 +- whilelo p5.b, tmp1, count +- b.last 1f +- st1b z0.b, p0, [dstin, #0, mul vl] +- st1b z0.b, p1, [dstin, #1, mul vl] +- st1b z0.b, p2, [dstin, #2, mul vl] +- st1b z0.b, p3, [dstin, #3, mul vl] +- st1b z0.b, p4, [dstin, #4, mul vl] +- st1b z0.b, p5, [dstin, #5, mul vl] +- ret +-1: lsl tmp1, vector_length, 2 // vector_length * 4 +- incb tmp1 // vector_length * 5 +- incb tmp1 // vector_length * 6 +- whilelo p6.b, tmp1, count +- incb tmp1 +- whilelo p7.b, tmp1, count +- st1b z0.b, p0, [dstin, #0, mul vl] +- st1b z0.b, p1, [dstin, #1, mul vl] +- st1b z0.b, p2, [dstin, #2, mul vl] +- st1b z0.b, p3, [dstin, #3, mul vl] +- st1b z0.b, p4, [dstin, #4, mul vl] +- st1b z0.b, p5, [dstin, #5, mul vl] +- st1b z0.b, p6, [dstin, #6, mul vl] +- st1b z0.b, p7, [dstin, #7, mul vl] +- ret +- .endm + +-ENTRY (MEMSET) ++#undef BTI_C ++#define BTI_C + ++ENTRY (MEMSET) + PTR_ARG (0) + SIZE_ARG (2) + +- cbnz count, 1f +- ret +-1: dup z0.b, valw + cntb vector_length +- // shortcut for less than vector_length * 8 +- // gives a free ptrue to p0.b for n >= vector_length +- shortcut_for_small_size L(vl_agnostic) +- // end of shortcut ++ dup z0.b, valw ++ whilelo p0.b, vector_length, count ++ b.last 1f ++ whilelo p1.b, xzr, count ++ st1b z0.b, p1, [dstin, 0, mul vl] ++ st1b z0.b, p0, [dstin, 1, mul vl] ++ ret ++ ++ // count >= vector_length * 2 ++1: cmp count, vector_length, lsl 2 ++ add dstend, dstin, count ++ b.hi 1f ++ st1b z0.b, p0, [dstin, 0, mul vl] ++ st1b z0.b, p0, [dstin, 1, mul vl] ++ st1b z0.b, p0, [dstend, -2, mul vl] ++ st1b z0.b, p0, [dstend, -1, mul vl] ++ ret ++ ++ // count > vector_length * 4 ++1: lsl tmp1, vector_length, 3 ++ cmp count, tmp1 ++ b.hi L(vl_agnostic) ++ st1b z0.b, p0, [dstin, 0, mul vl] ++ st1b z0.b, p0, [dstin, 1, mul vl] ++ st1b z0.b, p0, [dstin, 2, mul vl] ++ st1b z0.b, p0, [dstin, 3, mul vl] ++ st1b z0.b, p0, [dstend, -4, mul vl] ++ st1b z0.b, p0, [dstend, -3, mul vl] ++ st1b z0.b, p0, [dstend, -2, mul vl] ++ st1b z0.b, p0, [dstend, -1, mul vl] ++ ret + ++ .p2align 4 + L(vl_agnostic): // VL Agnostic + mov rest, count + mov dst, dstin +-- +1.8.3.1 + diff --git a/2-5-AArch64-Improve-A64FX-memset-for-large-sizes.patch b/2-5-AArch64-Improve-A64FX-memset-for-large-sizes.patch new file mode 100644 index 0000000000000000000000000000000000000000..81cdbe038153bf7f08099f86bacb538ab90c8550 --- /dev/null +++ b/2-5-AArch64-Improve-A64FX-memset-for-large-sizes.patch @@ -0,0 +1,131 @@ +From 9bc2ed8f46d80859a5596789cc9e8cc2de84b0e7 Mon Sep 17 00:00:00 2001 +From: Wilco Dijkstra +Date: Tue, 10 Aug 2021 13:39:37 +0100 +Subject: [PATCH] [2/5] AArch64: Improve A64FX memset for large sizes + +Improve performance of large memsets. Simplify alignment code. For zero memset +use DC ZVA, which almost doubles performance. For non-zero memsets use the +unroll8 loop which is about 10% faster. + +Reviewed-by: Naohiro Tamura +--- + sysdeps/aarch64/multiarch/memset_a64fx.S | 85 ++++++++++---------------------- + 1 file changed, 25 insertions(+), 60 deletions(-) + +diff --git a/sysdeps/aarch64/multiarch/memset_a64fx.S b/sysdeps/aarch64/multiarch/memset_a64fx.S +index cf3d402..75cf43a 100644 +--- a/sysdeps/aarch64/multiarch/memset_a64fx.S ++++ b/sysdeps/aarch64/multiarch/memset_a64fx.S +@@ -27,14 +27,11 @@ + */ + + #define L1_SIZE (64*1024) // L1 64KB +-#define L2_SIZE (8*1024*1024) // L2 8MB - 1MB ++#define L2_SIZE (8*1024*1024) // L2 8MB + #define CACHE_LINE_SIZE 256 + #define PF_DIST_L1 (CACHE_LINE_SIZE * 16) // Prefetch distance L1 +-#define ZF_DIST (CACHE_LINE_SIZE * 21) // Zerofill distance +-#define rest x8 ++#define rest x2 + #define vector_length x9 +-#define vl_remainder x10 // vector_length remainder +-#define cl_remainder x11 // CACHE_LINE_SIZE remainder + + #if HAVE_AARCH64_SVE_ASM + # if IS_IN (libc) +@@ -42,14 +39,6 @@ + + .arch armv8.2-a+sve + +- .macro dc_zva times +- dc zva, tmp1 +- add tmp1, tmp1, CACHE_LINE_SIZE +- .if \times-1 +- dc_zva "(\times-1)" +- .endif +- .endm +- + .macro st1b_unroll first=0, last=7 + st1b z0.b, p0, [dst, \first, mul vl] + .if \last-\first +@@ -188,54 +177,30 @@ L(L1_prefetch): // if rest >= L1_SIZE + cbnz rest, L(unroll32) + ret + +-L(L2): +- // align dst address at vector_length byte boundary +- sub tmp1, vector_length, 1 +- ands tmp2, dst, tmp1 +- // if vl_remainder == 0 +- b.eq 1f +- sub vl_remainder, vector_length, tmp2 +- // process remainder until the first vector_length boundary +- whilelt p2.b, xzr, vl_remainder +- st1b z0.b, p2, [dst] +- add dst, dst, vl_remainder +- sub rest, rest, vl_remainder +- // align dstin address at CACHE_LINE_SIZE byte boundary +-1: mov tmp1, CACHE_LINE_SIZE +- ands tmp2, dst, CACHE_LINE_SIZE - 1 +- // if cl_remainder == 0 +- b.eq L(L2_dc_zva) +- sub cl_remainder, tmp1, tmp2 +- // process remainder until the first CACHE_LINE_SIZE boundary +- mov tmp1, xzr // index +-2: whilelt p2.b, tmp1, cl_remainder +- st1b z0.b, p2, [dst, tmp1] +- incb tmp1 +- cmp tmp1, cl_remainder +- b.lo 2b +- add dst, dst, cl_remainder +- sub rest, rest, cl_remainder +- +-L(L2_dc_zva): +- // zero fill +- mov tmp1, dst +- dc_zva (ZF_DIST / CACHE_LINE_SIZE) - 1 +- mov zva_len, ZF_DIST +- add tmp1, zva_len, CACHE_LINE_SIZE * 2 +- // unroll ++ // count >= L2_SIZE + .p2align 3 +-1: st1b_unroll 0, 3 +- add tmp2, dst, zva_len +- dc zva, tmp2 +- st1b_unroll 4, 7 +- add tmp2, tmp2, CACHE_LINE_SIZE +- dc zva, tmp2 +- add dst, dst, CACHE_LINE_SIZE * 2 +- sub rest, rest, CACHE_LINE_SIZE * 2 +- cmp rest, tmp1 // ZF_DIST + CACHE_LINE_SIZE * 2 +- b.ge 1b +- cbnz rest, L(unroll8) +- ret ++L(L2): ++ tst valw, 255 ++ b.ne L(unroll8) ++ // align dst to CACHE_LINE_SIZE byte boundary ++ and tmp2, dst, CACHE_LINE_SIZE - 1 ++ st1b z0.b, p0, [dst, 0, mul vl] ++ st1b z0.b, p0, [dst, 1, mul vl] ++ st1b z0.b, p0, [dst, 2, mul vl] ++ st1b z0.b, p0, [dst, 3, mul vl] ++ sub dst, dst, tmp2 ++ add count, count, tmp2 ++ ++ // clear cachelines using DC ZVA ++ sub count, count, CACHE_LINE_SIZE * 2 ++ .p2align 4 ++1: add dst, dst, CACHE_LINE_SIZE ++ dc zva, dst ++ subs count, count, CACHE_LINE_SIZE ++ b.hi 1b ++ add count, count, CACHE_LINE_SIZE ++ add dst, dst, CACHE_LINE_SIZE ++ b L(last) + + END (MEMSET) + libc_hidden_builtin_def (MEMSET) +-- +1.8.3.1 + diff --git a/3-5-AArch64-Improve-A64FX-memset-for-remaining-bytes.patch b/3-5-AArch64-Improve-A64FX-memset-for-remaining-bytes.patch new file mode 100644 index 0000000000000000000000000000000000000000..7ba35160157681add3051dc033c2782f84c22cb9 --- /dev/null +++ b/3-5-AArch64-Improve-A64FX-memset-for-remaining-bytes.patch @@ -0,0 +1,80 @@ +From 186092c6ba8825598ffdbf15dbf0823c771f560d Mon Sep 17 00:00:00 2001 +From: Wilco Dijkstra +Date: Tue, 10 Aug 2021 13:42:07 +0100 +Subject: [PATCH] [3/5] AArch64: Improve A64FX memset for remaining bytes + +Simplify handling of remaining bytes. Avoid lots of taken branches and complex +whilelo computations, instead unconditionally write vectors from the end. + +Reviewed-by: Naohiro Tamura +--- + sysdeps/aarch64/multiarch/memset_a64fx.S | 46 +++++++++----------------------- + 1 file changed, 13 insertions(+), 33 deletions(-) + +diff --git a/sysdeps/aarch64/multiarch/memset_a64fx.S b/sysdeps/aarch64/multiarch/memset_a64fx.S +index 75cf43a..337c86b 100644 +--- a/sysdeps/aarch64/multiarch/memset_a64fx.S ++++ b/sysdeps/aarch64/multiarch/memset_a64fx.S +@@ -130,38 +130,19 @@ L(unroll8): + b 1b + + L(last): +- whilelo p0.b, xzr, rest +- whilelo p1.b, vector_length, rest +- b.last 1f +- st1b z0.b, p0, [dst, #0, mul vl] +- st1b z0.b, p1, [dst, #1, mul vl] +- ret +-1: lsl tmp1, vector_length, 1 // vector_length * 2 +- whilelo p2.b, tmp1, rest +- incb tmp1 +- whilelo p3.b, tmp1, rest +- b.last 1f +- st1b z0.b, p0, [dst, #0, mul vl] +- st1b z0.b, p1, [dst, #1, mul vl] +- st1b z0.b, p2, [dst, #2, mul vl] +- st1b z0.b, p3, [dst, #3, mul vl] +- ret +-1: lsl tmp1, vector_length, 2 // vector_length * 4 +- whilelo p4.b, tmp1, rest +- incb tmp1 +- whilelo p5.b, tmp1, rest +- incb tmp1 +- whilelo p6.b, tmp1, rest +- incb tmp1 +- whilelo p7.b, tmp1, rest +- st1b z0.b, p0, [dst, #0, mul vl] +- st1b z0.b, p1, [dst, #1, mul vl] +- st1b z0.b, p2, [dst, #2, mul vl] +- st1b z0.b, p3, [dst, #3, mul vl] +- st1b z0.b, p4, [dst, #4, mul vl] +- st1b z0.b, p5, [dst, #5, mul vl] +- st1b z0.b, p6, [dst, #6, mul vl] +- st1b z0.b, p7, [dst, #7, mul vl] ++ cmp count, vector_length, lsl 1 ++ b.ls 2f ++ add tmp2, vector_length, vector_length, lsl 2 ++ cmp count, tmp2 ++ b.ls 5f ++ st1b z0.b, p0, [dstend, -8, mul vl] ++ st1b z0.b, p0, [dstend, -7, mul vl] ++ st1b z0.b, p0, [dstend, -6, mul vl] ++5: st1b z0.b, p0, [dstend, -5, mul vl] ++ st1b z0.b, p0, [dstend, -4, mul vl] ++ st1b z0.b, p0, [dstend, -3, mul vl] ++2: st1b z0.b, p0, [dstend, -2, mul vl] ++ st1b z0.b, p0, [dstend, -1, mul vl] + ret + + L(L1_prefetch): // if rest >= L1_SIZE +@@ -199,7 +180,6 @@ L(L2): + subs count, count, CACHE_LINE_SIZE + b.hi 1b + add count, count, CACHE_LINE_SIZE +- add dst, dst, CACHE_LINE_SIZE + b L(last) + + END (MEMSET) +-- +1.8.3.1 + diff --git a/4-5-AArch64-Improve-A64FX-memset-by-removing-unroll3.patch b/4-5-AArch64-Improve-A64FX-memset-by-removing-unroll3.patch new file mode 100644 index 0000000000000000000000000000000000000000..fd176710033f0dd03a04542b998b246a0349a6c6 --- /dev/null +++ b/4-5-AArch64-Improve-A64FX-memset-by-removing-unroll3.patch @@ -0,0 +1,51 @@ +From e69d9981f858a38e19304e6ff5ebdf89f2cb0ba0 Mon Sep 17 00:00:00 2001 +From: Wilco Dijkstra +Date: Tue, 10 Aug 2021 13:44:27 +0100 +Subject: [PATCH] [4/5] AArch64: Improve A64FX memset by removing unroll32 + +Remove unroll32 code since it doesn't improve performance. + +Reviewed-by: Naohiro Tamura +--- + sysdeps/aarch64/multiarch/memset_a64fx.S | 18 +----------------- + 1 file changed, 1 insertion(+), 17 deletions(-) + +diff --git a/sysdeps/aarch64/multiarch/memset_a64fx.S b/sysdeps/aarch64/multiarch/memset_a64fx.S +index 337c86b..ef03156 100644 +--- a/sysdeps/aarch64/multiarch/memset_a64fx.S ++++ b/sysdeps/aarch64/multiarch/memset_a64fx.S +@@ -102,22 +102,6 @@ L(vl_agnostic): // VL Agnostic + ccmp vector_length, tmp1, 0, cs + b.eq L(L1_prefetch) + +-L(unroll32): +- lsl tmp1, vector_length, 3 // vector_length * 8 +- lsl tmp2, vector_length, 5 // vector_length * 32 +- .p2align 3 +-1: cmp rest, tmp2 +- b.cc L(unroll8) +- st1b_unroll +- add dst, dst, tmp1 +- st1b_unroll +- add dst, dst, tmp1 +- st1b_unroll +- add dst, dst, tmp1 +- st1b_unroll +- add dst, dst, tmp1 +- sub rest, rest, tmp2 +- b 1b + + L(unroll8): + lsl tmp1, vector_length, 3 +@@ -155,7 +139,7 @@ L(L1_prefetch): // if rest >= L1_SIZE + sub rest, rest, CACHE_LINE_SIZE * 2 + cmp rest, L1_SIZE + b.ge 1b +- cbnz rest, L(unroll32) ++ cbnz rest, L(unroll8) + ret + + // count >= L2_SIZE +-- +1.8.3.1 + diff --git a/5-5-AArch64-Improve-A64FX-memset-medium-loops.patch b/5-5-AArch64-Improve-A64FX-memset-medium-loops.patch new file mode 100644 index 0000000000000000000000000000000000000000..f8bc03e6150c98185e227fea69034114e97cbfdb --- /dev/null +++ b/5-5-AArch64-Improve-A64FX-memset-medium-loops.patch @@ -0,0 +1,96 @@ +From a5db6a5cae6a92d1675c013e5c8d972768721576 Mon Sep 17 00:00:00 2001 +From: Wilco Dijkstra +Date: Tue, 10 Aug 2021 13:46:20 +0100 +Subject: [PATCH] [5/5] AArch64: Improve A64FX memset medium loops + +Simplify the code for memsets smaller than L1. Improve the unroll8 and +L1_prefetch loops. + +Reviewed-by: Naohiro Tamura +--- + sysdeps/aarch64/multiarch/memset_a64fx.S | 45 ++++++++++++++------------------ + 1 file changed, 19 insertions(+), 26 deletions(-) + +diff --git a/sysdeps/aarch64/multiarch/memset_a64fx.S b/sysdeps/aarch64/multiarch/memset_a64fx.S +index ef03156..7bf759b 100644 +--- a/sysdeps/aarch64/multiarch/memset_a64fx.S ++++ b/sysdeps/aarch64/multiarch/memset_a64fx.S +@@ -30,7 +30,6 @@ + #define L2_SIZE (8*1024*1024) // L2 8MB + #define CACHE_LINE_SIZE 256 + #define PF_DIST_L1 (CACHE_LINE_SIZE * 16) // Prefetch distance L1 +-#define rest x2 + #define vector_length x9 + + #if HAVE_AARCH64_SVE_ASM +@@ -89,29 +88,19 @@ ENTRY (MEMSET) + + .p2align 4 + L(vl_agnostic): // VL Agnostic +- mov rest, count + mov dst, dstin +- add dstend, dstin, count +- // if rest >= L2_SIZE && vector_length == 64 then L(L2) +- mov tmp1, 64 +- cmp rest, L2_SIZE +- ccmp vector_length, tmp1, 0, cs +- b.eq L(L2) +- // if rest >= L1_SIZE && vector_length == 64 then L(L1_prefetch) +- cmp rest, L1_SIZE +- ccmp vector_length, tmp1, 0, cs +- b.eq L(L1_prefetch) +- ++ cmp count, L1_SIZE ++ b.hi L(L1_prefetch) + ++ // count >= 8 * vector_length + L(unroll8): +- lsl tmp1, vector_length, 3 +- .p2align 3 +-1: cmp rest, tmp1 +- b.cc L(last) +- st1b_unroll ++ sub count, count, tmp1 ++ .p2align 4 ++1: st1b_unroll 0, 7 + add dst, dst, tmp1 +- sub rest, rest, tmp1 +- b 1b ++ subs count, count, tmp1 ++ b.hi 1b ++ add count, count, tmp1 + + L(last): + cmp count, vector_length, lsl 1 +@@ -129,18 +118,22 @@ L(last): + st1b z0.b, p0, [dstend, -1, mul vl] + ret + +-L(L1_prefetch): // if rest >= L1_SIZE ++ // count >= L1_SIZE + .p2align 3 ++L(L1_prefetch): ++ cmp count, L2_SIZE ++ b.hs L(L2) ++ cmp vector_length, 64 ++ b.ne L(unroll8) + 1: st1b_unroll 0, 3 + prfm pstl1keep, [dst, PF_DIST_L1] + st1b_unroll 4, 7 + prfm pstl1keep, [dst, PF_DIST_L1 + CACHE_LINE_SIZE] + add dst, dst, CACHE_LINE_SIZE * 2 +- sub rest, rest, CACHE_LINE_SIZE * 2 +- cmp rest, L1_SIZE +- b.ge 1b +- cbnz rest, L(unroll8) +- ret ++ sub count, count, CACHE_LINE_SIZE * 2 ++ cmp count, PF_DIST_L1 ++ b.hs 1b ++ b L(unroll8) + + // count >= L2_SIZE + .p2align 3 +-- +1.8.3.1 + diff --git a/AArch64-Check-for-SVE-in-ifuncs-BZ-28744.patch b/AArch64-Check-for-SVE-in-ifuncs-BZ-28744.patch new file mode 100644 index 0000000000000000000000000000000000000000..1c41ca37f7447e088a0728c5c1fdbb7cdd878652 --- /dev/null +++ b/AArch64-Check-for-SVE-in-ifuncs-BZ-28744.patch @@ -0,0 +1,55 @@ +From e5fa62b8db546f8792ec9e5c61e6419f4f8e3f4d Mon Sep 17 00:00:00 2001 +From: Wilco Dijkstra +Date: Thu, 6 Jan 2022 14:36:28 +0000 +Subject: [PATCH] AArch64: Check for SVE in ifuncs [BZ #28744] + +Add a check for SVE in the A64FX ifuncs for memcpy, memset and memmove. +This fixes BZ #28744. +--- + sysdeps/aarch64/multiarch/memcpy.c | 2 +- + sysdeps/aarch64/multiarch/memmove.c | 2 +- + sysdeps/aarch64/multiarch/memset.c | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/sysdeps/aarch64/multiarch/memcpy.c b/sysdeps/aarch64/multiarch/memcpy.c +index 7dac7b7..a476dd5 100644 +--- a/sysdeps/aarch64/multiarch/memcpy.c ++++ b/sysdeps/aarch64/multiarch/memcpy.c +@@ -48,7 +48,7 @@ libc_ifunc (__libc_memcpy, + || IS_NEOVERSE_V1 (midr) + ? __memcpy_simd + # if HAVE_AARCH64_SVE_ASM +- : (IS_A64FX (midr) ++ : (IS_A64FX (midr) && sve + ? __memcpy_a64fx + : __memcpy_generic)))))); + # else +diff --git a/sysdeps/aarch64/multiarch/memmove.c b/sysdeps/aarch64/multiarch/memmove.c +index 48f8e46..4f7d7ee 100644 +--- a/sysdeps/aarch64/multiarch/memmove.c ++++ b/sysdeps/aarch64/multiarch/memmove.c +@@ -48,7 +48,7 @@ libc_ifunc (__libc_memmove, + || IS_NEOVERSE_V1 (midr) + ? __memmove_simd + # if HAVE_AARCH64_SVE_ASM +- : (IS_A64FX (midr) ++ : (IS_A64FX (midr) && sve + ? __memmove_a64fx + : __memmove_generic)))))); + # else +diff --git a/sysdeps/aarch64/multiarch/memset.c b/sysdeps/aarch64/multiarch/memset.c +index 3692b07..c4008f3 100644 +--- a/sysdeps/aarch64/multiarch/memset.c ++++ b/sysdeps/aarch64/multiarch/memset.c +@@ -44,7 +44,7 @@ libc_ifunc (__libc_memset, + : (IS_EMAG (midr) && zva_size == 64 + ? __memset_emag + # if HAVE_AARCH64_SVE_ASM +- : (IS_A64FX (midr) ++ : (IS_A64FX (midr) && sve + ? __memset_a64fx + : __memset_generic)))); + # else +-- +1.8.3.1 + diff --git a/AArch64-Update-A64FX-memset-not-to-degrade-at-16KB.patch b/AArch64-Update-A64FX-memset-not-to-degrade-at-16KB.patch new file mode 100644 index 0000000000000000000000000000000000000000..f7ce84d2d510140196eab38d24c48361bbc93f2f --- /dev/null +++ b/AArch64-Update-A64FX-memset-not-to-degrade-at-16KB.patch @@ -0,0 +1,39 @@ +From 23777232c23f80809613bdfa329f63aadf992922 Mon Sep 17 00:00:00 2001 +From: Naohiro Tamura via Libc-alpha +Date: Fri, 27 Aug 2021 05:03:04 +0000 +Subject: [PATCH] AArch64: Update A64FX memset not to degrade at 16KB + +This patch updates unroll8 code so as not to degrade at the peak +performance 16KB for both FX1000 and FX700. + +Inserted 2 instructions at the beginning of the unroll8 loop, +cmp and branch, are a workaround that is found heuristically. + +Reviewed-by: Wilco Dijkstra +--- + sysdeps/aarch64/multiarch/memset_a64fx.S | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/sysdeps/aarch64/multiarch/memset_a64fx.S b/sysdeps/aarch64/multiarch/memset_a64fx.S +index 7bf759b..f7dfdaa 100644 +--- a/sysdeps/aarch64/multiarch/memset_a64fx.S ++++ b/sysdeps/aarch64/multiarch/memset_a64fx.S +@@ -96,7 +96,14 @@ L(vl_agnostic): // VL Agnostic + L(unroll8): + sub count, count, tmp1 + .p2align 4 +-1: st1b_unroll 0, 7 ++ // The 2 instructions at the beginning of the following loop, ++ // cmp and branch, are a workaround so as not to degrade at ++ // the peak performance 16KB. ++ // It is found heuristically and the branch condition, b.ne, ++ // is chosen intentionally never to jump. ++1: cmp xzr, xzr ++ b.ne 1b ++ st1b_unroll 0, 7 + add dst, dst, tmp1 + subs count, count, tmp1 + b.hi 1b +-- +1.8.3.1 + diff --git a/Add-PTRACE_GET_RSEQ_CONFIGURATION-from-Linux-5.13-to.patch b/Add-PTRACE_GET_RSEQ_CONFIGURATION-from-Linux-5.13-to.patch new file mode 100644 index 0000000000000000000000000000000000000000..a11a56ef090f3fbe7f769eaa8b0d789a08bfc2aa --- /dev/null +++ b/Add-PTRACE_GET_RSEQ_CONFIGURATION-from-Linux-5.13-to.patch @@ -0,0 +1,216 @@ +From 98149b16d645e9644a8e9b3d1f4b7932b9b193c5 Mon Sep 17 00:00:00 2001 +From: Joseph Myers +Date: Mon, 9 Aug 2021 16:51:38 +0000 +Subject: [PATCH] Add PTRACE_GET_RSEQ_CONFIGURATION from Linux 5.13 to + sys/ptrace.h + +Linux 5.13 adds a PTRACE_GET_RSEQ_CONFIGURATION constant, with an +associated ptrace_rseq_configuration structure. + +Add this constant to the various sys/ptrace.h headers in glibc, with +the structure in bits/ptrace-shared.h (named struct +__ptrace_rseq_configuration in glibc, as with other such structures). + +Tested for x86_64, and with build-many-glibcs.py. + +--- + sysdeps/unix/sysv/linux/aarch64/sys/ptrace.h | 7 ++++++- + sysdeps/unix/sysv/linux/arm/sys/ptrace.h | 6 +++++- + sysdeps/unix/sysv/linux/bits/ptrace-shared.h | 10 ++++++++++ + sysdeps/unix/sysv/linux/ia64/sys/ptrace.h | 6 +++++- + sysdeps/unix/sysv/linux/powerpc/sys/ptrace.h | 7 ++++++- + sysdeps/unix/sysv/linux/s390/sys/ptrace.h | 5 +++++ + sysdeps/unix/sysv/linux/sparc/sys/ptrace.h | 6 +++++- + sysdeps/unix/sysv/linux/sys/ptrace.h | 6 +++++- + sysdeps/unix/sysv/linux/x86/sys/ptrace.h | 6 +++++- + 9 files changed, 52 insertions(+), 7 deletions(-) + +diff --git a/sysdeps/unix/sysv/linux/aarch64/sys/ptrace.h b/sysdeps/unix/sysv/linux/aarch64/sys/ptrace.h +index af8193cbe7b2..1fae1dce9c6a 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/sys/ptrace.h ++++ b/sysdeps/unix/sysv/linux/aarch64/sys/ptrace.h +@@ -58,6 +58,7 @@ __BEGIN_DECLS + #undef PTRACE_SECCOMP_GET_FILTER + #undef PTRACE_SECCOMP_GET_METADATA + #undef PTRACE_GET_SYSCALL_INFO ++#undef PTRACE_GET_RSEQ_CONFIGURATION + + /* Type of the REQUEST argument to `ptrace.' */ + enum __ptrace_request +@@ -190,8 +191,12 @@ enum __ptrace_request + #define PTRACE_SECCOMP_GET_METADATA PTRACE_SECCOMP_GET_METADATA + + /* Get information about system call. */ +- PTRACE_GET_SYSCALL_INFO = 0x420e ++ PTRACE_GET_SYSCALL_INFO = 0x420e, + #define PTRACE_GET_SYSCALL_INFO PTRACE_GET_SYSCALL_INFO ++ ++ /* Get rseq configuration information. */ ++ PTRACE_GET_RSEQ_CONFIGURATION = 0x420f ++#define PTRACE_GET_RSEQ_CONFIGURATION PTRACE_GET_RSEQ_CONFIGURATION + }; + + +diff --git a/sysdeps/unix/sysv/linux/arm/sys/ptrace.h b/sysdeps/unix/sysv/linux/arm/sys/ptrace.h +index cdb1f159a7c1..2e3843664855 100644 +--- a/sysdeps/unix/sysv/linux/arm/sys/ptrace.h ++++ b/sysdeps/unix/sysv/linux/arm/sys/ptrace.h +@@ -200,8 +200,12 @@ enum __ptrace_request + #define PTRACE_SECCOMP_GET_METADATA PTRACE_SECCOMP_GET_METADATA + + /* Get information about system call. */ +- PTRACE_GET_SYSCALL_INFO = 0x420e ++ PTRACE_GET_SYSCALL_INFO = 0x420e, + #define PTRACE_GET_SYSCALL_INFO PTRACE_GET_SYSCALL_INFO ++ ++ /* Get rseq configuration information. */ ++ PTRACE_GET_RSEQ_CONFIGURATION = 0x420f ++#define PTRACE_GET_RSEQ_CONFIGURATION PTRACE_GET_RSEQ_CONFIGURATION + }; + + +diff --git a/sysdeps/unix/sysv/linux/bits/ptrace-shared.h b/sysdeps/unix/sysv/linux/bits/ptrace-shared.h +index 7d40634da55e..7e95ca7082e9 100644 +--- a/sysdeps/unix/sysv/linux/bits/ptrace-shared.h ++++ b/sysdeps/unix/sysv/linux/bits/ptrace-shared.h +@@ -120,6 +120,16 @@ struct __ptrace_syscall_info + }; + }; + ++/* Results of PTRACE_GET_RSEQ_CONFIGURATION. */ ++struct __ptrace_rseq_configuration ++{ ++ __uint64_t rseq_abi_pointer; ++ __uint32_t rseq_abi_size; ++ __uint32_t signature; ++ __uint32_t flags; ++ __uint32_t pad; ++}; ++ + /* Perform process tracing functions. REQUEST is one of the values + above, and determines the action to be taken. + For all requests except PTRACE_TRACEME, PID specifies the process to be +diff --git a/sysdeps/unix/sysv/linux/ia64/sys/ptrace.h b/sysdeps/unix/sysv/linux/ia64/sys/ptrace.h +index bea975bb9e3d..536a0cafbd1b 100644 +--- a/sysdeps/unix/sysv/linux/ia64/sys/ptrace.h ++++ b/sysdeps/unix/sysv/linux/ia64/sys/ptrace.h +@@ -153,8 +153,12 @@ enum __ptrace_request + #define PTRACE_SECCOMP_GET_METADATA PTRACE_SECCOMP_GET_METADATA + + /* Get information about system call. */ +- PTRACE_GET_SYSCALL_INFO = 0x420e ++ PTRACE_GET_SYSCALL_INFO = 0x420e, + #define PTRACE_GET_SYSCALL_INFO PTRACE_GET_SYSCALL_INFO ++ ++ /* Get rseq configuration information. */ ++ PTRACE_GET_RSEQ_CONFIGURATION = 0x420f ++#define PTRACE_GET_RSEQ_CONFIGURATION PTRACE_GET_RSEQ_CONFIGURATION + }; + + +diff --git a/sysdeps/unix/sysv/linux/powerpc/sys/ptrace.h b/sysdeps/unix/sysv/linux/powerpc/sys/ptrace.h +index 032c91e81791..fb599af6da64 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/sys/ptrace.h ++++ b/sysdeps/unix/sysv/linux/powerpc/sys/ptrace.h +@@ -36,6 +36,7 @@ __BEGIN_DECLS + # undef PTRACE_GETREGS + # undef PTRACE_GETREGS64 + # undef PTRACE_GETREGSET ++# undef PTRACE_GET_RSEQ_CONFIGURATION + # undef PTRACE_GETSIGINFO + # undef PTRACE_GETSIGMASK + # undef PTRACE_GET_SYSCALL_INFO +@@ -260,8 +261,12 @@ enum __ptrace_request + #define PTRACE_SECCOMP_GET_METADATA PTRACE_SECCOMP_GET_METADATA + + /* Get information about system call. */ +- PTRACE_GET_SYSCALL_INFO = 0x420e ++ PTRACE_GET_SYSCALL_INFO = 0x420e, + #define PTRACE_GET_SYSCALL_INFO PTRACE_GET_SYSCALL_INFO ++ ++ /* Get rseq configuration information. */ ++ PTRACE_GET_RSEQ_CONFIGURATION = 0x420f ++#define PTRACE_GET_RSEQ_CONFIGURATION PTRACE_GET_RSEQ_CONFIGURATION + }; + + +diff --git a/sysdeps/unix/sysv/linux/s390/sys/ptrace.h b/sysdeps/unix/sysv/linux/s390/sys/ptrace.h +index 4f3c65726f61..3ddd2e426789 100644 +--- a/sysdeps/unix/sysv/linux/s390/sys/ptrace.h ++++ b/sysdeps/unix/sysv/linux/s390/sys/ptrace.h +@@ -86,6 +86,7 @@ __BEGIN_DECLS + # undef PTRACE_SYSCALL_INFO_ENTRY + # undef PTRACE_SYSCALL_INFO_EXIT + # undef PTRACE_SYSCALL_INFO_SECCOMP ++# undef PTRACE_GET_RSEQ_CONFIGURATION + #endif + /* Type of the REQUEST argument to `ptrace.' */ + enum __ptrace_request +@@ -217,6 +218,10 @@ enum __ptrace_request + PTRACE_GET_SYSCALL_INFO = 0x420e, + #define PTRACE_GET_SYSCALL_INFO PTRACE_GET_SYSCALL_INFO + ++ /* Get rseq configuration information. */ ++ PTRACE_GET_RSEQ_CONFIGURATION = 0x420f, ++#define PTRACE_GET_RSEQ_CONFIGURATION PTRACE_GET_RSEQ_CONFIGURATION ++ + PTRACE_PEEKUSR_AREA = 0x5000, + #define PTRACE_PEEKUSR_AREA PTRACE_PEEKUSR_AREA + +diff --git a/sysdeps/unix/sysv/linux/sparc/sys/ptrace.h b/sysdeps/unix/sysv/linux/sparc/sys/ptrace.h +index 3f6150028487..773b4379249c 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sys/ptrace.h ++++ b/sysdeps/unix/sysv/linux/sparc/sys/ptrace.h +@@ -221,8 +221,12 @@ enum __ptrace_request + #define PTRACE_SECCOMP_GET_METADATA PTRACE_SECCOMP_GET_METADATA + + /* Get information about system call. */ +- PTRACE_GET_SYSCALL_INFO = 0x420e ++ PTRACE_GET_SYSCALL_INFO = 0x420e, + #define PTRACE_GET_SYSCALL_INFO PTRACE_GET_SYSCALL_INFO ++ ++ /* Get rseq configuration information. */ ++ PTRACE_GET_RSEQ_CONFIGURATION = 0x420f ++#define PTRACE_GET_RSEQ_CONFIGURATION PTRACE_GET_RSEQ_CONFIGURATION + }; + + +diff --git a/sysdeps/unix/sysv/linux/sys/ptrace.h b/sysdeps/unix/sysv/linux/sys/ptrace.h +index dc76e97ea72a..404fc3ddb7b5 100644 +--- a/sysdeps/unix/sysv/linux/sys/ptrace.h ++++ b/sysdeps/unix/sysv/linux/sys/ptrace.h +@@ -170,8 +170,12 @@ enum __ptrace_request + #define PTRACE_SECCOMP_GET_METADATA PTRACE_SECCOMP_GET_METADATA + + /* Get information about system call. */ +- PTRACE_GET_SYSCALL_INFO = 0x420e ++ PTRACE_GET_SYSCALL_INFO = 0x420e, + #define PTRACE_GET_SYSCALL_INFO PTRACE_GET_SYSCALL_INFO ++ ++ /* Get rseq configuration information. */ ++ PTRACE_GET_RSEQ_CONFIGURATION = 0x420f ++#define PTRACE_GET_RSEQ_CONFIGURATION PTRACE_GET_RSEQ_CONFIGURATION + }; + + +diff --git a/sysdeps/unix/sysv/linux/x86/sys/ptrace.h b/sysdeps/unix/sysv/linux/x86/sys/ptrace.h +index 8501cc22ed7b..7202a09eefd3 100644 +--- a/sysdeps/unix/sysv/linux/x86/sys/ptrace.h ++++ b/sysdeps/unix/sysv/linux/x86/sys/ptrace.h +@@ -190,8 +190,12 @@ enum __ptrace_request + #define PTRACE_SECCOMP_GET_METADATA PTRACE_SECCOMP_GET_METADATA + + /* Get information about system call. */ +- PTRACE_GET_SYSCALL_INFO = 0x420e ++ PTRACE_GET_SYSCALL_INFO = 0x420e, + #define PTRACE_GET_SYSCALL_INFO PTRACE_GET_SYSCALL_INFO ++ ++ /* Get rseq configuration information. */ ++ PTRACE_GET_RSEQ_CONFIGURATION = 0x420f ++#define PTRACE_GET_RSEQ_CONFIGURATION PTRACE_GET_RSEQ_CONFIGURATION + }; + + +-- +2.27.0 + diff --git a/Avoid-warning-overriding-recipe-for-.-tst-ro-dynamic.patch b/Avoid-warning-overriding-recipe-for-.-tst-ro-dynamic.patch new file mode 100644 index 0000000000000000000000000000000000000000..60576f4a05ff79470f55a5306ea6f78c9aef8697 --- /dev/null +++ b/Avoid-warning-overriding-recipe-for-.-tst-ro-dynamic.patch @@ -0,0 +1,34 @@ +From 15e6d6785ac2935bb963506b47a37b3d1f728952 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Fri, 24 Sep 2021 08:56:42 -0700 +Subject: [PATCH] Avoid warning: overriding recipe for + .../tst-ro-dynamic-mod.so + +Add tst-ro-dynamic-mod to modules-names-nobuild to avoid + +../Makerules:767: warning: ignoring old recipe for target '.../elf/tst-ro-dynamic-mod.so' + +This updates BZ #28340 fix. +--- + elf/Makefile | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/elf/Makefile b/elf/Makefile +index 0cdccaa..26986c0 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -402,8 +402,9 @@ endif + modules-execstack-yes = tst-execstack-mod + extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) + +-# filtmod1.so, tst-big-note-lib.so have special rules. +-modules-names-nobuild := filtmod1 tst-big-note-lib ++# filtmod1.so, tst-big-note-lib.so, tst-ro-dynamic-mod.so have special ++# rules. ++modules-names-nobuild := filtmod1 tst-big-note-lib tst-ro-dynamic-mod + + tests += $(tests-static) + +-- +1.8.3.1 + diff --git a/CVE-2022-23218-Buffer-overflow-in-sunrpc-svcunix_cre.patch b/CVE-2022-23218-Buffer-overflow-in-sunrpc-svcunix_cre.patch new file mode 100644 index 0000000000000000000000000000000000000000..401059db32f5eba7110655b438e395c95c96858c --- /dev/null +++ b/CVE-2022-23218-Buffer-overflow-in-sunrpc-svcunix_cre.patch @@ -0,0 +1,125 @@ +From f545ad4928fa1f27a3075265182b38a4f939a5f7 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Mon, 17 Jan 2022 10:21:34 +0100 +Subject: [PATCH] CVE-2022-23218: Buffer overflow in sunrpc svcunix_create (bug + 28768) + +The sunrpc function svcunix_create suffers from a stack-based buffer +overflow with overlong pathname arguments. + +Reviewed-by: Siddhesh Poyarekar +--- + NEWS | 3 +++ + sunrpc/Makefile | 2 +- + sunrpc/svc_unix.c | 11 ++++------- + sunrpc/tst-bug28768.c | 42 ++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 50 insertions(+), 8 deletions(-) + create mode 100644 sunrpc/tst-bug28768.c + +diff --git a/NEWS b/NEWS +index 38a9ddb..38802f0 100644 +--- a/NEWS ++++ b/NEWS +@@ -14,6 +14,9 @@ Security related changes: + legacy function could result in a stack-based buffer overflow when + using the "unix" protocol. Reported by Martin Sebor. + ++ CVE-2022-23218: Passing an overlong file name to the svcunix_create ++ legacy function could result in a stack-based buffer overflow. ++ + The following bugs are resolved with this release: + + [22542] CVE-2022-23219: Buffer overflow in sunrpc clnt_create for "unix" +diff --git a/sunrpc/Makefile b/sunrpc/Makefile +index 183ef3d..a79a719 100644 +--- a/sunrpc/Makefile ++++ b/sunrpc/Makefile +@@ -65,7 +65,7 @@ shared-only-routines = $(routines) + endif + + tests = tst-xdrmem tst-xdrmem2 test-rpcent tst-udp-error tst-udp-timeout \ +- tst-udp-nonblocking tst-bug22542 ++ tst-udp-nonblocking tst-bug22542 tst-bug28768 + + xtests := tst-getmyaddr + +diff --git a/sunrpc/svc_unix.c b/sunrpc/svc_unix.c +index f2280b4..67177a2 100644 +--- a/sunrpc/svc_unix.c ++++ b/sunrpc/svc_unix.c +@@ -154,7 +154,10 @@ svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path) + SVCXPRT *xprt; + struct unix_rendezvous *r; + struct sockaddr_un addr; +- socklen_t len = sizeof (struct sockaddr_in); ++ socklen_t len = sizeof (addr); ++ ++ if (__sockaddr_un_set (&addr, path) < 0) ++ return NULL; + + if (sock == RPC_ANYSOCK) + { +@@ -165,12 +168,6 @@ svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path) + } + madesock = TRUE; + } +- memset (&addr, '\0', sizeof (addr)); +- addr.sun_family = AF_UNIX; +- len = strlen (path) + 1; +- memcpy (addr.sun_path, path, len); +- len += sizeof (addr.sun_family); +- + __bind (sock, (struct sockaddr *) &addr, len); + + if (__getsockname (sock, (struct sockaddr *) &addr, &len) != 0 +diff --git a/sunrpc/tst-bug28768.c b/sunrpc/tst-bug28768.c +new file mode 100644 +index 0000000..35a4b7b +--- /dev/null ++++ b/sunrpc/tst-bug28768.c +@@ -0,0 +1,42 @@ ++/* Test to verify that long path is rejected by svcunix_create (bug 28768). ++ Copyright (C) 2022 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* svcunix_create does not have a default version in linkobj/libc.so. */ ++compat_symbol_reference (libc, svcunix_create, svcunix_create, GLIBC_2_1); ++ ++static int ++do_test (void) ++{ ++ char pathname[109]; ++ memset (pathname, 'x', sizeof (pathname)); ++ pathname[sizeof (pathname) - 1] = '\0'; ++ ++ errno = 0; ++ TEST_VERIFY (svcunix_create (RPC_ANYSOCK, 4096, 4096, pathname) == NULL); ++ TEST_COMPARE (errno, EINVAL); ++ ++ return 0; ++} ++ ++#include +-- +1.8.3.1 + diff --git a/CVE-2022-23219-Buffer-overflow-in-sunrpc-clnt_create.patch b/CVE-2022-23219-Buffer-overflow-in-sunrpc-clnt_create.patch new file mode 100644 index 0000000000000000000000000000000000000000..f5b048847d9d24d0da4a7b387846d19253634d62 --- /dev/null +++ b/CVE-2022-23219-Buffer-overflow-in-sunrpc-clnt_create.patch @@ -0,0 +1,65 @@ +From 226b46770c82899b555986583294b049c6ec9b40 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Mon, 17 Jan 2022 10:21:34 +0100 +Subject: [PATCH] CVE-2022-23219: Buffer overflow in sunrpc clnt_create for + "unix" (bug 22542) + +Processing an overlong pathname in the sunrpc clnt_create function +results in a stack-based buffer overflow. + +Reviewed-by: Siddhesh Poyarekar + +--- + NEWS | 14 ++++++++++++++ + sunrpc/clnt_gen.c | 10 +++++++--- + 2 files changed, 21 insertions(+), 3 deletions(-) + +diff --git a/NEWS b/NEWS +index 3c610744..dbe6f086 100644 +--- a/NEWS ++++ b/NEWS +@@ -4,6 +4,20 @@ See the end for copying conditions. + + Please send GNU C library bug reports via + using `glibc' in the "product" field. ++ ++^L ++Version 2.34.1 ++ ++Security related changes: ++ ++ CVE-2022-23219: Passing an overlong file name to the clnt_create ++ legacy function could result in a stack-based buffer overflow when ++ using the "unix" protocol. Reported by Martin Sebor. ++ ++The following bugs are resolved with this release: ++ ++ [22542] CVE-2022-23219: Buffer overflow in sunrpc clnt_create for "unix" ++ + + Version 2.34 + +diff --git a/sunrpc/clnt_gen.c b/sunrpc/clnt_gen.c +index 13ced899..b44357cd 100644 +--- a/sunrpc/clnt_gen.c ++++ b/sunrpc/clnt_gen.c +@@ -57,9 +57,13 @@ clnt_create (const char *hostname, u_long prog, u_long vers, + + if (strcmp (proto, "unix") == 0) + { +- memset ((char *)&sun, 0, sizeof (sun)); +- sun.sun_family = AF_UNIX; +- strcpy (sun.sun_path, hostname); ++ if (__sockaddr_un_set (&sun, hostname) < 0) ++ { ++ struct rpc_createerr *ce = &get_rpc_createerr (); ++ ce->cf_stat = RPC_SYSTEMERROR; ++ ce->cf_error.re_errno = errno; ++ return NULL; ++ } + sock = RPC_ANYSOCK; + client = clntunix_create (&sun, prog, vers, &sock, 0, 0); + if (client == NULL) +-- +2.27.0 + diff --git a/Disable-debuginfod-in-printer-tests-BZ-28757.patch b/Disable-debuginfod-in-printer-tests-BZ-28757.patch new file mode 100644 index 0000000000000000000000000000000000000000..a701f434002beb3b68b2da1cba12681b7d9e013d --- /dev/null +++ b/Disable-debuginfod-in-printer-tests-BZ-28757.patch @@ -0,0 +1,57 @@ +From 7de501f9418bf099e7104b63b0e4423257981b14 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Sun, 9 Jan 2022 09:06:15 -0800 +Subject: [PATCH] Disable debuginfod in printer tests [BZ #28757] + +With gdb-11.1-6.fc35.x86_64, I got + +FAIL: nptl/test-cond-printers +FAIL: nptl/test-condattr-printers +FAIL: nptl/test-mutex-printers +FAIL: nptl/test-mutexattr-printers +FAIL: nptl/test-rwlock-printers +FAIL: nptl/test-rwlockattr-printers + +$ cat nptl/test-condattr-printers.out +Error: Response does not match the expected pattern. +Command: start +Expected pattern: main +Response: Temporary breakpoint 1 at 0x11d5: file test-condattr-printers.c, line 43. +Starting program: /export/build/gnu/tools-build/glibc-cet-gitlab/build-x86_64-linux/nptl/test-condattr-printers + +This GDB supports auto-downloading debuginfo from the following URLs: +https://debuginfod.fedoraproject.org/ +Enable debuginfod for this session? (y or [n]) + +Disable debuginfod to avoid GDB messages. This fixes BZ #28757. + +Reviewed-by: Florian Weimer +--- + scripts/test_printers_common.py | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/scripts/test_printers_common.py b/scripts/test_printers_common.py +index 6406e3bac7..38121697bc 100644 +--- a/scripts/test_printers_common.py ++++ b/scripts/test_printers_common.py +@@ -161,6 +161,17 @@ def init_test(test_bin, printer_files, printer_names): + printer files. + """ + ++ # Disable debuginfod to avoid GDB messages like: ++ # ++ # This GDB supports auto-downloading debuginfo from the following URLs: ++ # https://debuginfod.fedoraproject.org/ ++ # Enable debuginfod for this session? (y or [n]) ++ # ++ try: ++ test('set debuginfod enabled off') ++ except Exception: ++ pass ++ + # Load all the pretty printer files. We're assuming these are safe. + for printer_file in printer_files: + test('source {0}'.format(printer_file)) +-- +2.27.0 + diff --git a/Do-not-define-tgmath.h-fmaxmag-fminmag-macros-for-C2.patch b/Do-not-define-tgmath.h-fmaxmag-fminmag-macros-for-C2.patch new file mode 100644 index 0000000000000000000000000000000000000000..ce25968f0bbbd400aef9c3feb878106d0326d995 --- /dev/null +++ b/Do-not-define-tgmath.h-fmaxmag-fminmag-macros-for-C2.patch @@ -0,0 +1,37 @@ +From 79850e1025aabeccd3586c32ca259aa854607582 Mon Sep 17 00:00:00 2001 +From: Joseph Myers +Date: Wed, 29 Sep 2021 17:38:32 +0000 +Subject: [PATCH] Do not define tgmath.h fmaxmag, fminmag macros for C2X (bug + 28397) + +C2X does not include fmaxmag and fminmag. When I updated feature test +macro handling accordingly (commit +858045ad1c5ac1682288bbcb3676632b97a21ddf, "Update floating-point +feature test macro handling for C2X", included in 2.34), I missed +updating tgmath.h so it doesn't define the corresponding type-generic +macros unless __STDC_WANT_IEC_60559_BFP_EXT__ is defined; I've now +reported this as bug 28397. Adjust the conditionals in tgmath.h +accordingly. + +Tested for x86_64. +--- + math/tgmath.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/math/tgmath.h b/math/tgmath.h +index 9868353..3d7b099 100644 +--- a/math/tgmath.h ++++ b/math/tgmath.h +@@ -921,7 +921,9 @@ + + /* Like ilogb, but returning long int. */ + # define llogb(Val) __TGMATH_UNARY_REAL_RET_ONLY (Val, llogb) ++#endif + ++#if __GLIBC_USE (IEC_60559_BFP_EXT) + /* Return value with maximum magnitude. */ + # define fmaxmag(Val1, Val2) __TGMATH_BINARY_REAL_ONLY (Val1, Val2, fmaxmag) + +-- +1.8.3.1 + diff --git a/Fix-failing-nss-tst-nss-files-hosts-long-with-local-.patch b/Fix-failing-nss-tst-nss-files-hosts-long-with-local-.patch new file mode 100644 index 0000000000000000000000000000000000000000..f9cb581bdca739cb58554db8aab0d6392fdf2d56 --- /dev/null +++ b/Fix-failing-nss-tst-nss-files-hosts-long-with-local-.patch @@ -0,0 +1,37 @@ +From ae925404a10bf0ea63d6e8d41e3821f68b4d776c Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Fri, 3 Sep 2021 00:28:14 +0200 +Subject: [PATCH] Fix failing nss/tst-nss-files-hosts-long with local resolver + +When a local resolver like unbound is listening on the IPv4 loopback +address 127.0.0.1, the nss/tst-nss-files-hosts-long test fails. This is +due to: +- the default resolver in the absence of resolv.conf being 127.0.0.1 +- the default DNS NSS database configuration in the absence of + nsswitch.conf being 'hosts: dns [!UNAVAIL=return] file' + +This causes the requests for 'test4' and 'test6' to first be sent to the +local resolver, which responds with NXDOMAIN in the likely case those +records do no exist. In turn that causes the access to /etc/hosts to be +skipped, which is the purpose of that test. + +Fix that by providing a simple nsswitch.conf file forcing access to +/etc/hosts for that test. I have tested that the only changed result in +the testsuite is that test. + +(cherry picked from commit 2738480a4b0866723fb8c633f36bdd34a8767581) +--- + nss/tst-nss-files-hosts-long.root/etc/nsswitch.conf | 1 + + 1 file changed, 1 insertion(+) + create mode 100644 nss/tst-nss-files-hosts-long.root/etc/nsswitch.conf + +diff --git a/nss/tst-nss-files-hosts-long.root/etc/nsswitch.conf b/nss/tst-nss-files-hosts-long.root/etc/nsswitch.conf +new file mode 100644 +index 0000000..5b0c6a4 +--- /dev/null ++++ b/nss/tst-nss-files-hosts-long.root/etc/nsswitch.conf +@@ -0,0 +1 @@ ++hosts: files +-- +1.8.3.1 + diff --git a/Fix-glibc-2.34-ABI-omission-missing-GLIBC_2.34-in-dy.patch b/Fix-glibc-2.34-ABI-omission-missing-GLIBC_2.34-in-dy.patch new file mode 100644 index 0000000000000000000000000000000000000000..bc38a377ce825a27023c2387f3b7e7fad9b2b40b --- /dev/null +++ b/Fix-glibc-2.34-ABI-omission-missing-GLIBC_2.34-in-dy.patch @@ -0,0 +1,399 @@ +From 948ebc098ed3cd928ea10997f990115e7770bda3 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Thu, 27 Jan 2022 16:03:58 +0100 +Subject: [PATCH] Fix glibc 2.34 ABI omission (missing GLIBC_2.34 in dynamic + loader) + +The glibc 2.34 release really should have added a GLIBC_2.34 +symbol to the dynamic loader. With it, we could move functions such +as dlopen or pthread_key_create that work on process-global state +into the dynamic loader (once we have fixed a longstanding issue +with static linking). Without the GLIBC_2.34 symbol, yet another +new symbol version would be needed because old glibc will fail to +load binaries due to the missing symbol version in ld.so that newly +linked programs will require. + +Reviewed-by: H.J. Lu +(cherry picked from commit af121ae3e7cd12628c91ecfc46a9d65313a6e972) +--- + elf/Makefile | 1 + + elf/Versions | 3 ++ + elf/dl-compat.c | 32 +++++++++++++++++++ + sysdeps/mach/hurd/i386/ld.abilist | 1 + + sysdeps/unix/sysv/linux/aarch64/ld.abilist | 1 + + sysdeps/unix/sysv/linux/alpha/ld.abilist | 1 + + sysdeps/unix/sysv/linux/arc/ld.abilist | 1 + + sysdeps/unix/sysv/linux/arm/be/ld.abilist | 1 + + sysdeps/unix/sysv/linux/arm/le/ld.abilist | 1 + + sysdeps/unix/sysv/linux/csky/ld.abilist | 1 + + sysdeps/unix/sysv/linux/hppa/ld.abilist | 1 + + sysdeps/unix/sysv/linux/i386/ld.abilist | 1 + + sysdeps/unix/sysv/linux/ia64/ld.abilist | 1 + + .../unix/sysv/linux/m68k/coldfire/ld.abilist | 1 + + .../unix/sysv/linux/m68k/m680x0/ld.abilist | 1 + + sysdeps/unix/sysv/linux/microblaze/ld.abilist | 1 + + .../unix/sysv/linux/mips/mips32/ld.abilist | 1 + + .../sysv/linux/mips/mips64/n32/ld.abilist | 1 + + .../sysv/linux/mips/mips64/n64/ld.abilist | 1 + + sysdeps/unix/sysv/linux/nios2/ld.abilist | 1 + + .../sysv/linux/powerpc/powerpc32/ld.abilist | 1 + + .../linux/powerpc/powerpc64/be/ld.abilist | 1 + + .../linux/powerpc/powerpc64/le/ld.abilist | 1 + + sysdeps/unix/sysv/linux/riscv/rv32/ld.abilist | 1 + + sysdeps/unix/sysv/linux/riscv/rv64/ld.abilist | 1 + + .../unix/sysv/linux/s390/s390-32/ld.abilist | 1 + + .../unix/sysv/linux/s390/s390-64/ld.abilist | 1 + + sysdeps/unix/sysv/linux/sh/be/ld.abilist | 1 + + sysdeps/unix/sysv/linux/sh/le/ld.abilist | 1 + + .../unix/sysv/linux/sparc/sparc32/ld.abilist | 1 + + .../unix/sysv/linux/sparc/sparc64/ld.abilist | 1 + + sysdeps/unix/sysv/linux/x86_64/64/ld.abilist | 1 + + sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist | 1 + + 33 files changed, 66 insertions(+) + create mode 100644 elf/dl-compat.c + +diff --git a/elf/Makefile b/elf/Makefile +index f930e04e27..af4ccb978c 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -115,6 +115,7 @@ elide-routines.os = \ + # interpreter and operating independent of libc. + rtld-routines = \ + $(all-dl-routines) \ ++ dl-compat \ + dl-conflict \ + dl-diagnostics \ + dl-diagnostics-cpu \ +diff --git a/elf/Versions b/elf/Versions +index 775aab62af..2af210b8f7 100644 +--- a/elf/Versions ++++ b/elf/Versions +@@ -48,6 +48,9 @@ ld { + # stack canary + __stack_chk_guard; + } ++ GLIBC_2.34 { ++ __rtld_version_placeholder; ++ } + GLIBC_PRIVATE { + # Those are in the dynamic linker, but used by libc.so. + __libc_enable_secure; +diff --git a/elf/dl-compat.c b/elf/dl-compat.c +new file mode 100644 +index 0000000000..cc560c5159 +--- /dev/null ++++ b/elf/dl-compat.c +@@ -0,0 +1,32 @@ ++/* Placeholder compatibility symbols. ++ Copyright (C) 2022 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 ++ . */ ++ ++#include ++#include ++ ++/* GLIBC_2.34 placeholder for future symbol moves. */ ++ ++void ++attribute_compat_text_section ++__attribute_used__ ++__rtld_version_placeholder_1 (void) ++{ ++} ++ ++compat_symbol (ld, __rtld_version_placeholder_1, ++ __rtld_version_placeholder, GLIBC_2_34); +diff --git a/sysdeps/mach/hurd/i386/ld.abilist b/sysdeps/mach/hurd/i386/ld.abilist +index 7e20c5e7ce..ebba31f770 100644 +--- a/sysdeps/mach/hurd/i386/ld.abilist ++++ b/sysdeps/mach/hurd/i386/ld.abilist +@@ -16,3 +16,4 @@ GLIBC_2.2.6 _r_debug D 0x14 + GLIBC_2.2.6 abort F + GLIBC_2.3 ___tls_get_addr F + GLIBC_2.3 __tls_get_addr F ++GLIBC_2.34 __rtld_version_placeholder F +diff --git a/sysdeps/unix/sysv/linux/aarch64/ld.abilist b/sysdeps/unix/sysv/linux/aarch64/ld.abilist +index 80b2fe6725..b7196a80e2 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/aarch64/ld.abilist +@@ -3,3 +3,4 @@ GLIBC_2.17 __stack_chk_guard D 0x8 + GLIBC_2.17 __tls_get_addr F + GLIBC_2.17 _dl_mcount F + GLIBC_2.17 _r_debug D 0x28 ++GLIBC_2.34 __rtld_version_placeholder F +diff --git a/sysdeps/unix/sysv/linux/alpha/ld.abilist b/sysdeps/unix/sysv/linux/alpha/ld.abilist +index 98a03f611f..13f7fc74af 100644 +--- a/sysdeps/unix/sysv/linux/alpha/ld.abilist ++++ b/sysdeps/unix/sysv/linux/alpha/ld.abilist +@@ -2,4 +2,5 @@ GLIBC_2.0 _r_debug D 0x28 + GLIBC_2.1 __libc_stack_end D 0x8 + GLIBC_2.1 _dl_mcount F + GLIBC_2.3 __tls_get_addr F ++GLIBC_2.34 __rtld_version_placeholder F + GLIBC_2.4 __stack_chk_guard D 0x8 +diff --git a/sysdeps/unix/sysv/linux/arc/ld.abilist b/sysdeps/unix/sysv/linux/arc/ld.abilist +index 048f17c848..7284383a6b 100644 +--- a/sysdeps/unix/sysv/linux/arc/ld.abilist ++++ b/sysdeps/unix/sysv/linux/arc/ld.abilist +@@ -3,3 +3,4 @@ GLIBC_2.32 __stack_chk_guard D 0x4 + GLIBC_2.32 __tls_get_addr F + GLIBC_2.32 _dl_mcount F + GLIBC_2.32 _r_debug D 0x14 ++GLIBC_2.34 __rtld_version_placeholder F +diff --git a/sysdeps/unix/sysv/linux/arm/be/ld.abilist b/sysdeps/unix/sysv/linux/arm/be/ld.abilist +index cc8825c3bc..7987bbae11 100644 +--- a/sysdeps/unix/sysv/linux/arm/be/ld.abilist ++++ b/sysdeps/unix/sysv/linux/arm/be/ld.abilist +@@ -1,3 +1,4 @@ ++GLIBC_2.34 __rtld_version_placeholder F + GLIBC_2.4 __libc_stack_end D 0x4 + GLIBC_2.4 __stack_chk_guard D 0x4 + GLIBC_2.4 __tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/arm/le/ld.abilist b/sysdeps/unix/sysv/linux/arm/le/ld.abilist +index cc8825c3bc..7987bbae11 100644 +--- a/sysdeps/unix/sysv/linux/arm/le/ld.abilist ++++ b/sysdeps/unix/sysv/linux/arm/le/ld.abilist +@@ -1,3 +1,4 @@ ++GLIBC_2.34 __rtld_version_placeholder F + GLIBC_2.4 __libc_stack_end D 0x4 + GLIBC_2.4 __stack_chk_guard D 0x4 + GLIBC_2.4 __tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/csky/ld.abilist b/sysdeps/unix/sysv/linux/csky/ld.abilist +index 564ac09737..4939b20631 100644 +--- a/sysdeps/unix/sysv/linux/csky/ld.abilist ++++ b/sysdeps/unix/sysv/linux/csky/ld.abilist +@@ -3,3 +3,4 @@ GLIBC_2.29 __stack_chk_guard D 0x4 + GLIBC_2.29 __tls_get_addr F + GLIBC_2.29 _dl_mcount F + GLIBC_2.29 _r_debug D 0x14 ++GLIBC_2.34 __rtld_version_placeholder F +diff --git a/sysdeps/unix/sysv/linux/hppa/ld.abilist b/sysdeps/unix/sysv/linux/hppa/ld.abilist +index d155a59843..7cc9ebd792 100644 +--- a/sysdeps/unix/sysv/linux/hppa/ld.abilist ++++ b/sysdeps/unix/sysv/linux/hppa/ld.abilist +@@ -2,4 +2,5 @@ GLIBC_2.2 __libc_stack_end D 0x4 + GLIBC_2.2 _dl_mcount F + GLIBC_2.2 _r_debug D 0x14 + GLIBC_2.3 __tls_get_addr F ++GLIBC_2.34 __rtld_version_placeholder F + GLIBC_2.4 __stack_chk_guard D 0x4 +diff --git a/sysdeps/unix/sysv/linux/i386/ld.abilist b/sysdeps/unix/sysv/linux/i386/ld.abilist +index 0478e22071..e8d187b14d 100644 +--- a/sysdeps/unix/sysv/linux/i386/ld.abilist ++++ b/sysdeps/unix/sysv/linux/i386/ld.abilist +@@ -3,3 +3,4 @@ GLIBC_2.1 __libc_stack_end D 0x4 + GLIBC_2.1 _dl_mcount F + GLIBC_2.3 ___tls_get_addr F + GLIBC_2.3 __tls_get_addr F ++GLIBC_2.34 __rtld_version_placeholder F +diff --git a/sysdeps/unix/sysv/linux/ia64/ld.abilist b/sysdeps/unix/sysv/linux/ia64/ld.abilist +index 33f91199bf..be5122650a 100644 +--- a/sysdeps/unix/sysv/linux/ia64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/ia64/ld.abilist +@@ -2,3 +2,4 @@ GLIBC_2.2 __libc_stack_end D 0x8 + GLIBC_2.2 _dl_mcount F + GLIBC_2.2 _r_debug D 0x28 + GLIBC_2.3 __tls_get_addr F ++GLIBC_2.34 __rtld_version_placeholder F +diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/ld.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/ld.abilist +index cc8825c3bc..7987bbae11 100644 +--- a/sysdeps/unix/sysv/linux/m68k/coldfire/ld.abilist ++++ b/sysdeps/unix/sysv/linux/m68k/coldfire/ld.abilist +@@ -1,3 +1,4 @@ ++GLIBC_2.34 __rtld_version_placeholder F + GLIBC_2.4 __libc_stack_end D 0x4 + GLIBC_2.4 __stack_chk_guard D 0x4 + GLIBC_2.4 __tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/ld.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/ld.abilist +index 3ba474c27f..4f2854edf7 100644 +--- a/sysdeps/unix/sysv/linux/m68k/m680x0/ld.abilist ++++ b/sysdeps/unix/sysv/linux/m68k/m680x0/ld.abilist +@@ -2,4 +2,5 @@ GLIBC_2.0 _r_debug D 0x14 + GLIBC_2.1 __libc_stack_end D 0x4 + GLIBC_2.1 _dl_mcount F + GLIBC_2.3 __tls_get_addr F ++GLIBC_2.34 __rtld_version_placeholder F + GLIBC_2.4 __stack_chk_guard D 0x4 +diff --git a/sysdeps/unix/sysv/linux/microblaze/ld.abilist b/sysdeps/unix/sysv/linux/microblaze/ld.abilist +index a4933c3541..9f0fdeca38 100644 +--- a/sysdeps/unix/sysv/linux/microblaze/ld.abilist ++++ b/sysdeps/unix/sysv/linux/microblaze/ld.abilist +@@ -3,3 +3,4 @@ GLIBC_2.18 __stack_chk_guard D 0x4 + GLIBC_2.18 __tls_get_addr F + GLIBC_2.18 _dl_mcount F + GLIBC_2.18 _r_debug D 0x14 ++GLIBC_2.34 __rtld_version_placeholder F +diff --git a/sysdeps/unix/sysv/linux/mips/mips32/ld.abilist b/sysdeps/unix/sysv/linux/mips/mips32/ld.abilist +index be09641a48..f750067d5c 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/mips/mips32/ld.abilist +@@ -2,4 +2,5 @@ GLIBC_2.0 _r_debug D 0x14 + GLIBC_2.2 __libc_stack_end D 0x4 + GLIBC_2.2 _dl_mcount F + GLIBC_2.3 __tls_get_addr F ++GLIBC_2.34 __rtld_version_placeholder F + GLIBC_2.4 __stack_chk_guard D 0x4 +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/ld.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/ld.abilist +index be09641a48..f750067d5c 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/ld.abilist +@@ -2,4 +2,5 @@ GLIBC_2.0 _r_debug D 0x14 + GLIBC_2.2 __libc_stack_end D 0x4 + GLIBC_2.2 _dl_mcount F + GLIBC_2.3 __tls_get_addr F ++GLIBC_2.34 __rtld_version_placeholder F + GLIBC_2.4 __stack_chk_guard D 0x4 +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist +index 1ea36e13f2..2fba6a9b6e 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist +@@ -2,4 +2,5 @@ GLIBC_2.0 _r_debug D 0x28 + GLIBC_2.2 __libc_stack_end D 0x8 + GLIBC_2.2 _dl_mcount F + GLIBC_2.3 __tls_get_addr F ++GLIBC_2.34 __rtld_version_placeholder F + GLIBC_2.4 __stack_chk_guard D 0x8 +diff --git a/sysdeps/unix/sysv/linux/nios2/ld.abilist b/sysdeps/unix/sysv/linux/nios2/ld.abilist +index 52178802dd..57dfad5a53 100644 +--- a/sysdeps/unix/sysv/linux/nios2/ld.abilist ++++ b/sysdeps/unix/sysv/linux/nios2/ld.abilist +@@ -3,3 +3,4 @@ GLIBC_2.21 __stack_chk_guard D 0x4 + GLIBC_2.21 __tls_get_addr F + GLIBC_2.21 _dl_mcount F + GLIBC_2.21 _r_debug D 0x14 ++GLIBC_2.34 __rtld_version_placeholder F +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/ld.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/ld.abilist +index 4bbfba7a61..e896607392 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/ld.abilist +@@ -4,3 +4,4 @@ GLIBC_2.1 _dl_mcount F + GLIBC_2.22 __tls_get_addr_opt F + GLIBC_2.23 __parse_hwcap_and_convert_at_platform F + GLIBC_2.3 __tls_get_addr F ++GLIBC_2.34 __rtld_version_placeholder F +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/ld.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/ld.abilist +index 283fb4510b..ce0bc63959 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/ld.abilist ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/ld.abilist +@@ -4,3 +4,4 @@ GLIBC_2.3 __libc_stack_end D 0x8 + GLIBC_2.3 __tls_get_addr F + GLIBC_2.3 _dl_mcount F + GLIBC_2.3 _r_debug D 0x28 ++GLIBC_2.34 __rtld_version_placeholder F +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/ld.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/ld.abilist +index b1f313c7cd..65b22674d2 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/ld.abilist ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/ld.abilist +@@ -4,3 +4,4 @@ GLIBC_2.17 _dl_mcount F + GLIBC_2.17 _r_debug D 0x28 + GLIBC_2.22 __tls_get_addr_opt F + GLIBC_2.23 __parse_hwcap_and_convert_at_platform F ++GLIBC_2.34 __rtld_version_placeholder F +diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/ld.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/ld.abilist +index 94ca64c43d..5ad4c81d12 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/riscv/rv32/ld.abilist +@@ -3,3 +3,4 @@ GLIBC_2.33 __stack_chk_guard D 0x4 + GLIBC_2.33 __tls_get_addr F + GLIBC_2.33 _dl_mcount F + GLIBC_2.33 _r_debug D 0x14 ++GLIBC_2.34 __rtld_version_placeholder F +diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/ld.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/ld.abilist +index 845f356c3c..479efdea9b 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/riscv/rv64/ld.abilist +@@ -3,3 +3,4 @@ GLIBC_2.27 __stack_chk_guard D 0x8 + GLIBC_2.27 __tls_get_addr F + GLIBC_2.27 _dl_mcount F + GLIBC_2.27 _r_debug D 0x28 ++GLIBC_2.34 __rtld_version_placeholder F +diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/ld.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/ld.abilist +index b56f005beb..d5ecb636bb 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/s390/s390-32/ld.abilist +@@ -2,3 +2,4 @@ GLIBC_2.0 _r_debug D 0x14 + GLIBC_2.1 __libc_stack_end D 0x4 + GLIBC_2.1 _dl_mcount F + GLIBC_2.3 __tls_get_offset F ++GLIBC_2.34 __rtld_version_placeholder F +diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist +index 6f788a086d..62a5e1d99a 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist +@@ -2,3 +2,4 @@ GLIBC_2.2 __libc_stack_end D 0x8 + GLIBC_2.2 _dl_mcount F + GLIBC_2.2 _r_debug D 0x28 + GLIBC_2.3 __tls_get_offset F ++GLIBC_2.34 __rtld_version_placeholder F +diff --git a/sysdeps/unix/sysv/linux/sh/be/ld.abilist b/sysdeps/unix/sysv/linux/sh/be/ld.abilist +index d155a59843..7cc9ebd792 100644 +--- a/sysdeps/unix/sysv/linux/sh/be/ld.abilist ++++ b/sysdeps/unix/sysv/linux/sh/be/ld.abilist +@@ -2,4 +2,5 @@ GLIBC_2.2 __libc_stack_end D 0x4 + GLIBC_2.2 _dl_mcount F + GLIBC_2.2 _r_debug D 0x14 + GLIBC_2.3 __tls_get_addr F ++GLIBC_2.34 __rtld_version_placeholder F + GLIBC_2.4 __stack_chk_guard D 0x4 +diff --git a/sysdeps/unix/sysv/linux/sh/le/ld.abilist b/sysdeps/unix/sysv/linux/sh/le/ld.abilist +index d155a59843..7cc9ebd792 100644 +--- a/sysdeps/unix/sysv/linux/sh/le/ld.abilist ++++ b/sysdeps/unix/sysv/linux/sh/le/ld.abilist +@@ -2,4 +2,5 @@ GLIBC_2.2 __libc_stack_end D 0x4 + GLIBC_2.2 _dl_mcount F + GLIBC_2.2 _r_debug D 0x14 + GLIBC_2.3 __tls_get_addr F ++GLIBC_2.34 __rtld_version_placeholder F + GLIBC_2.4 __stack_chk_guard D 0x4 +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/ld.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/ld.abilist +index 0c6610e3c2..2e60543498 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/sparc/sparc32/ld.abilist +@@ -2,3 +2,4 @@ GLIBC_2.0 _r_debug D 0x14 + GLIBC_2.1 __libc_stack_end D 0x4 + GLIBC_2.1 _dl_mcount F + GLIBC_2.3 __tls_get_addr F ++GLIBC_2.34 __rtld_version_placeholder F +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist +index 33f91199bf..be5122650a 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist +@@ -2,3 +2,4 @@ GLIBC_2.2 __libc_stack_end D 0x8 + GLIBC_2.2 _dl_mcount F + GLIBC_2.2 _r_debug D 0x28 + GLIBC_2.3 __tls_get_addr F ++GLIBC_2.34 __rtld_version_placeholder F +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist b/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist +index d3cdf7611e..afddaec57c 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist +@@ -2,3 +2,4 @@ GLIBC_2.2.5 __libc_stack_end D 0x8 + GLIBC_2.2.5 _dl_mcount F + GLIBC_2.2.5 _r_debug D 0x28 + GLIBC_2.3 __tls_get_addr F ++GLIBC_2.34 __rtld_version_placeholder F +diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist +index c70bccf782..defc488d13 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist +@@ -2,3 +2,4 @@ GLIBC_2.16 __libc_stack_end D 0x4 + GLIBC_2.16 __tls_get_addr F + GLIBC_2.16 _dl_mcount F + GLIBC_2.16 _r_debug D 0x14 ++GLIBC_2.34 __rtld_version_placeholder F +-- +2.27.0 + diff --git a/Fix-subscript-error-with-odd-TZif-file-BZ-28338.patch b/Fix-subscript-error-with-odd-TZif-file-BZ-28338.patch new file mode 100644 index 0000000000000000000000000000000000000000..3825b15eee9505e683fd4730eb166e703661f636 --- /dev/null +++ b/Fix-subscript-error-with-odd-TZif-file-BZ-28338.patch @@ -0,0 +1,31 @@ +From 645277434a42efc547d2cac8bfede4da10b4049f Mon Sep 17 00:00:00 2001 +From: Paul Eggert +Date: Mon, 13 Sep 2021 22:49:45 -0700 +Subject: [PATCH] Fix subscript error with odd TZif file [BZ #28338] + +* time/tzfile.c (__tzfile_compute): Fix unlikely off-by-one bug +that accessed before start of an array when an oddball-but-valid +TZif file was queried with an unusual time_t value. + +Reviewed-by: Adhemerval Zanella +--- + time/tzfile.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/time/tzfile.c b/time/tzfile.c +index 4377018..190a777 100644 +--- a/time/tzfile.c ++++ b/time/tzfile.c +@@ -765,8 +765,7 @@ __tzfile_compute (__time64_t timer, int use_localtime, + *leap_correct = leaps[i].change; + + if (timer == leaps[i].transition /* Exactly at the transition time. */ +- && ((i == 0 && leaps[i].change > 0) +- || leaps[i].change > leaps[i - 1].change)) ++ && (leaps[i].change > (i == 0 ? 0 : leaps[i - 1].change))) + { + *leap_hit = 1; + while (i > 0 +-- +1.8.3.1 + diff --git a/Handle-NULL-input-to-malloc_usable_size-BZ-28506.patch b/Handle-NULL-input-to-malloc_usable_size-BZ-28506.patch new file mode 100644 index 0000000000000000000000000000000000000000..9115fc4dde6fa0d0a5a1c1a52999d2f9c7013561 --- /dev/null +++ b/Handle-NULL-input-to-malloc_usable_size-BZ-28506.patch @@ -0,0 +1,158 @@ +From 01bffc013cdad1e0c45db7aa57efb2bee61f3338 Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +Date: Fri, 29 Oct 2021 14:53:55 +0530 +Subject: [PATCH] Handle NULL input to malloc_usable_size [BZ #28506] + +Hoist the NULL check for malloc_usable_size into its entry points in +malloc-debug and malloc and assume non-NULL in all callees. This fixes +BZ #28506 + +Signed-off-by: Siddhesh Poyarekar +Reviewed-by: Florian Weimer +Reviewed-by: Richard W.M. Jones +(cherry picked from commit 88e316b06414ee7c944cd6f8b30b07a972b78499) +--- + malloc/malloc-debug.c | 13 +++++++------ + malloc/malloc.c | 25 +++++++++---------------- + malloc/tst-malloc-usable.c | 22 +++++++++------------- + 3 files changed, 25 insertions(+), 35 deletions(-) + +diff --git a/malloc/malloc-debug.c b/malloc/malloc-debug.c +index 9922ef5..3d7e6d4 100644 +--- a/malloc/malloc-debug.c ++++ b/malloc/malloc-debug.c +@@ -1,5 +1,6 @@ + /* Malloc debug DSO. + Copyright (C) 2021 Free Software Foundation, Inc. ++ Copyright The GNU Toolchain Authors. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or +@@ -399,17 +400,17 @@ strong_alias (__debug_calloc, calloc) + size_t + malloc_usable_size (void *mem) + { ++ if (mem == NULL) ++ return 0; ++ + if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)) + return mcheck_usable_size (mem); + if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)) + return malloc_check_get_size (mem); + +- if (mem != NULL) +- { +- mchunkptr p = mem2chunk (mem); +- if (DUMPED_MAIN_ARENA_CHUNK (p)) +- return chunksize (p) - SIZE_SZ; +- } ++ mchunkptr p = mem2chunk (mem); ++ if (DUMPED_MAIN_ARENA_CHUNK (p)) ++ return chunksize (p) - SIZE_SZ; + + return musable (mem); + } +diff --git a/malloc/malloc.c b/malloc/malloc.c +index e065785..7882c70 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -1,5 +1,6 @@ + /* Malloc implementation for multiple threads without lock contention. + Copyright (C) 1996-2021 Free Software Foundation, Inc. ++ Copyright The GNU Toolchain Authors. + This file is part of the GNU C Library. + Contributed by Wolfram Gloger + and Doug Lea , 2001. +@@ -5009,20 +5010,13 @@ __malloc_trim (size_t s) + static size_t + musable (void *mem) + { +- mchunkptr p; +- if (mem != 0) +- { +- size_t result = 0; +- +- p = mem2chunk (mem); ++ mchunkptr p = mem2chunk (mem); + +- if (chunk_is_mmapped (p)) +- result = chunksize (p) - CHUNK_HDR_SZ; +- else if (inuse (p)) +- result = memsize (p); ++ if (chunk_is_mmapped (p)) ++ return chunksize (p) - CHUNK_HDR_SZ; ++ else if (inuse (p)) ++ return memsize (p); + +- return result; +- } + return 0; + } + +@@ -5030,10 +5024,9 @@ musable (void *mem) + size_t + __malloc_usable_size (void *m) + { +- size_t result; +- +- result = musable (m); +- return result; ++ if (m == NULL) ++ return 0; ++ return musable (m); + } + #endif + +diff --git a/malloc/tst-malloc-usable.c b/malloc/tst-malloc-usable.c +index a1074b7..b0d702b 100644 +--- a/malloc/tst-malloc-usable.c ++++ b/malloc/tst-malloc-usable.c +@@ -2,6 +2,7 @@ + MALLOC_CHECK_ exported to a positive value. + + Copyright (C) 2012-2021 Free Software Foundation, Inc. ++ Copyright The GNU Toolchain Authors. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or +@@ -21,29 +22,24 @@ + #include + #include + #include ++#include ++#include + + static int + do_test (void) + { + size_t usable_size; + void *p = malloc (7); +- if (!p) +- { +- printf ("memory allocation failed\n"); +- return 1; +- } + ++ TEST_VERIFY_EXIT (p != NULL); + usable_size = malloc_usable_size (p); +- if (usable_size != 7) +- { +- printf ("malloc_usable_size: expected 7 but got %zu\n", usable_size); +- return 1; +- } +- ++ TEST_COMPARE (usable_size, 7); + memset (p, 0, usable_size); + free (p); ++ ++ TEST_COMPARE (malloc_usable_size (NULL), 0); ++ + return 0; + } + +-#define TEST_FUNCTION do_test () +-#include "../test-skeleton.c" ++#include "support/test-driver.c" +-- +1.8.3.1 + diff --git a/Linux-Detect-user-namespace-support-in-io-tst-getcwd.patch b/Linux-Detect-user-namespace-support-in-io-tst-getcwd.patch new file mode 100644 index 0000000000000000000000000000000000000000..9ae3ffb73396906375a7b02b3ab3aab1d972009d --- /dev/null +++ b/Linux-Detect-user-namespace-support-in-io-tst-getcwd.patch @@ -0,0 +1,53 @@ +From 3438bbca90895d32825a52e31a77dc44d273c1c1 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Mon, 24 Jan 2022 18:14:24 +0100 +Subject: [PATCH] Linux: Detect user namespace support in + io/tst-getcwd-smallbuff + +Otherwise the test fails with certain container runtimes. + +Reviewed-by: Siddhesh Poyarekar +(cherry picked from commit 5b8e7980c5dabd9aaefeba4f0208baa8cf7653ee) +--- + sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c b/sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c +index d460d6e..55362f6 100644 +--- a/sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c ++++ b/sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -188,6 +189,23 @@ do_test (void) + xmkdir (MOUNT_NAME, S_IRWXU); + atexit (do_cleanup); + ++ /* Check whether user namespaces are supported. */ ++ { ++ pid_t pid = xfork (); ++ if (pid == 0) ++ { ++ if (unshare (CLONE_NEWUSER | CLONE_NEWNS) != 0) ++ _exit (EXIT_UNSUPPORTED); ++ else ++ _exit (0); ++ } ++ int status; ++ xwaitpid (pid, &status, 0); ++ TEST_VERIFY_EXIT (WIFEXITED (status)); ++ if (WEXITSTATUS (status) != 0) ++ return WEXITSTATUS (status); ++ } ++ + TEST_VERIFY_EXIT (socketpair (AF_UNIX, SOCK_STREAM, 0, sockfd) == 0); + pid_t child_pid = xclone (child_func, NULL, child_stack, + sizeof (child_stack), +-- +1.8.3.1 + diff --git a/Linux-Fix-fcntl-ioctl-prctl-redirects-for-_TIME_BITS.patch b/Linux-Fix-fcntl-ioctl-prctl-redirects-for-_TIME_BITS.patch new file mode 100644 index 0000000000000000000000000000000000000000..b33981de0a23215e05069e5251e4d5a825799c83 --- /dev/null +++ b/Linux-Fix-fcntl-ioctl-prctl-redirects-for-_TIME_BITS.patch @@ -0,0 +1,72 @@ +From c87fcacc50505d550f1bb038382bcc7ea73a5926 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 6 Aug 2021 09:51:38 +0200 +Subject: [PATCH] Linux: Fix fcntl, ioctl, prctl redirects for _TIME_BITS=64 + (bug 28182) + +__REDIRECT and __THROW are not compatible with C++ due to the ordering of the +__asm__ alias and the throw specifier. __REDIRECT_NTH has to be used +instead. + +Fixes commit 8a40aff86ba5f64a3a84883e539cb67b ("io: Add time64 alias +for fcntl"), commit 82c395d91ea4f69120d453aeec398e30 ("misc: Add +time64 alias for ioctl"), commit b39ffab860cd743a82c91946619f1b8158 +("Linux: Add time64 alias for prctl"). + +Reviewed-by: Carlos O'Donell +--- + io/fcntl.h | 8 ++++---- + misc/sys/ioctl.h | 4 ++-- + sysdeps/unix/sysv/linux/sys/prctl.h | 2 +- + 3 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/io/fcntl.h b/io/fcntl.h +index 8917a73..1c96f98 100644 +--- a/io/fcntl.h ++++ b/io/fcntl.h +@@ -187,10 +187,10 @@ extern int fcntl64 (int __fd, int __cmd, ...); + # endif + #else /* __USE_TIME_BITS64 */ + # ifdef __REDIRECT +-extern int __REDIRECT (fcntl, (int __fd, int __request, ...), +- __fcntl_time64) __THROW; +-extern int __REDIRECT (fcntl64, (int __fd, int __request, ...), +- __fcntl_time64) __THROW; ++extern int __REDIRECT_NTH (fcntl, (int __fd, int __request, ...), ++ __fcntl_time64); ++extern int __REDIRECT_NTH (fcntl64, (int __fd, int __request, ...), ++ __fcntl_time64); + # else + extern int __fcntl_time64 (int __fd, int __request, ...) __THROW; + # define fcntl64 __fcntl_time64 +diff --git a/misc/sys/ioctl.h b/misc/sys/ioctl.h +index 6884d99..9945c1e 100644 +--- a/misc/sys/ioctl.h ++++ b/misc/sys/ioctl.h +@@ -42,8 +42,8 @@ __BEGIN_DECLS + extern int ioctl (int __fd, unsigned long int __request, ...) __THROW; + #else + # ifdef __REDIRECT +-extern int __REDIRECT (ioctl, (int __fd, unsigned long int __request, ...), +- __ioctl_time64) __THROW; ++extern int __REDIRECT_NTH (ioctl, (int __fd, unsigned long int __request, ...), ++ __ioctl_time64); + # else + extern int __ioctl_time64 (int __fd, unsigned long int __request, ...) __THROW; + # define ioctl __ioctl_time64 +diff --git a/sysdeps/unix/sysv/linux/sys/prctl.h b/sysdeps/unix/sysv/linux/sys/prctl.h +index db88938..f0e0d2f 100644 +--- a/sysdeps/unix/sysv/linux/sys/prctl.h ++++ b/sysdeps/unix/sysv/linux/sys/prctl.h +@@ -42,7 +42,7 @@ __BEGIN_DECLS + extern int prctl (int __option, ...) __THROW; + #else + # ifdef __REDIRECT +-extern int __REDIRECT (prctl, (int __option, ...), __prctl_time64) __THROW; ++extern int __REDIRECT_NTH (prctl, (int __option, ...), __prctl_time64); + # else + extern int __prctl_time64 (int __option,d ...) __THROW; + # define ioctl __prctl_time64 +-- +1.8.3.1 + diff --git a/Linux-Only-generate-64-bit-timestamps-for-64-bit-tim.patch b/Linux-Only-generate-64-bit-timestamps-for-64-bit-tim.patch new file mode 100644 index 0000000000000000000000000000000000000000..45655a61bc371140ee4598d92e43dcbc90627dd6 --- /dev/null +++ b/Linux-Only-generate-64-bit-timestamps-for-64-bit-tim.patch @@ -0,0 +1,498 @@ +From 489d0b8b32548bc569cd3067aebf98b030720753 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Thu, 27 Jan 2022 16:45:18 -0300 +Subject: [PATCH] Linux: Only generate 64 bit timestamps for 64 bit time_t + recvmsg/recvmmsg + +The timestamps created by __convert_scm_timestamps only make sense for +64 bit time_t programs, 32 bit time_t programs will ignore 64 bit time_t +timestamps since SO_TIMESTAMP will be defined to old values (either by +glibc or kernel headers). + +Worse, if the buffer is not suffice MSG_CTRUNC is set to indicate it +(which breaks some programs [1]). + +This patch makes only 64 bit time_t recvmsg and recvmmsg to call +__convert_scm_timestamps. Also, the assumption to called it is changed +from __ASSUME_TIME64_SYSCALLS to __TIMESIZE != 64 since the setsockopt +might be called by libraries built without __TIME_BITS=64. The +MSG_CTRUNC is only set for the 64 bit symbols, it should happen only +if 64 bit time_t programs run older kernels. + +Checked on x86_64-linux-gnu and i686-linux-gnu. + +[1] https://github.com/systemd/systemd/pull/20567 + +Reviewed-by: Florian Weimer + +(cherry picked from commit 948ce73b31fdb0860bcec4b8e62b14e88234f98a) +--- + include/sys/socket.h | 10 +- + sysdeps/unix/sysv/linux/Makefile | 10 +- + sysdeps/unix/sysv/linux/recvmmsg.c | 36 ++- + sysdeps/unix/sysv/linux/recvmsg.c | 34 ++- + .../tst-socket-timestamp-compat-time64.c | 1 + + .../sysv/linux/tst-socket-timestamp-compat.c | 265 ++++++++++++++++++ + 6 files changed, 330 insertions(+), 26 deletions(-) + create mode 100644 sysdeps/unix/sysv/linux/tst-socket-timestamp-compat-time64.c + create mode 100644 sysdeps/unix/sysv/linux/tst-socket-timestamp-compat.c + +diff --git a/include/sys/socket.h b/include/sys/socket.h +index a1d749f9fa..6e4cf5077f 100644 +--- a/include/sys/socket.h ++++ b/include/sys/socket.h +@@ -98,15 +98,21 @@ extern int __sendmmsg (int __fd, struct mmsghdr *__vmessages, + libc_hidden_proto (__sendmmsg) + #endif + +-/* Receive a message as described by MESSAGE from socket FD. +- Returns the number of bytes read or -1 for errors. */ + extern ssize_t __libc_recvmsg (int __fd, struct msghdr *__message, + int __flags); + extern ssize_t __recvmsg (int __fd, struct msghdr *__message, + int __flags) attribute_hidden; + #if __TIMESIZE == 64 ++# define __libc_recvmsg64 __libc_recvmsg ++# define __recvmsg64 __recvmsg + # define __recvmmsg64 __recvmmsg + #else ++extern ssize_t __libc_recvmsg64 (int __fd, struct msghdr *__message, ++ int __flags); ++extern ssize_t __recvmsg64 (int __fd, struct msghdr *__message, ++ int __flags); ++/* Receive a message as described by MESSAGE from socket FD. ++ Returns the number of bytes read or -1 for errors. */ + extern int __recvmmsg64 (int __fd, struct mmsghdr *vmessages, + unsigned int vlen, int flags, + struct __timespec64 *timeout); +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index 964f641ef9..c34774806f 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -262,8 +262,14 @@ sysdep_routines += cmsg_nxthdr + CFLAGS-recvmmsg.c = -fexceptions -fasynchronous-unwind-tables + CFLAGS-sendmmsg.c = -fexceptions -fasynchronous-unwind-tables + +-tests += tst-socket-timestamp +-tests-time64 += tst-socket-timestamp-time64 ++tests += \ ++ tst-socket-timestamp \ ++ tst-socket-timestamp-compat \ ++ # tests ++tests-time64 += \ ++ tst-socket-timestamp-time64 \ ++ tst-socket-timestamp-compat-time64 ++ # tests-time64 + + tests-special += $(objpfx)tst-socket-consts.out + $(objpfx)tst-socket-consts.out: ../sysdeps/unix/sysv/linux/tst-socket-consts.py +diff --git a/sysdeps/unix/sysv/linux/recvmmsg.c b/sysdeps/unix/sysv/linux/recvmmsg.c +index 5cd107ffa9..fca9f6582d 100644 +--- a/sysdeps/unix/sysv/linux/recvmmsg.c ++++ b/sysdeps/unix/sysv/linux/recvmmsg.c +@@ -20,9 +20,9 @@ + #include + #include + +-int +-__recvmmsg64 (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags, +- struct __timespec64 *timeout) ++static int ++recvmmsg_syscall (int fd, struct mmsghdr *vmessages, unsigned int vlen, ++ int flags, struct __timespec64 *timeout) + { + #ifndef __NR_recvmmsg_time64 + # define __NR_recvmmsg_time64 __NR_recvmmsg +@@ -45,12 +45,6 @@ __recvmmsg64 (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags, + pts32 = &ts32; + } + +- socklen_t csize[IOV_MAX]; +- if (vlen > IOV_MAX) +- vlen = IOV_MAX; +- for (int i = 0; i < vlen; i++) +- csize[i] = vmessages[i].msg_hdr.msg_controllen; +- + # ifdef __ASSUME_RECVMMSG_SYSCALL + r = SYSCALL_CANCEL (recvmmsg, fd, vmessages, vlen, flags, pts32); + # else +@@ -60,11 +54,31 @@ __recvmmsg64 (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags, + { + if (timeout != NULL) + *timeout = valid_timespec_to_timespec64 (ts32); ++ } ++#endif ++ return r; ++} ++ ++int ++__recvmmsg64 (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags, ++ struct __timespec64 *timeout) ++{ ++#if __TIMESIZE != 64 ++ socklen_t csize[IOV_MAX]; ++ if (vlen > IOV_MAX) ++ vlen = IOV_MAX; ++ for (int i = 0; i < vlen; i++) ++ csize[i] = vmessages[i].msg_hdr.msg_controllen; ++#endif + ++ int r = recvmmsg_syscall (fd, vmessages, vlen, flags, timeout); ++#if __TIMESIZE != 64 ++ if (r > 0) ++ { + for (int i=0; i < r; i++) + __convert_scm_timestamps (&vmessages[i].msg_hdr, csize[i]); + } +-#endif /* __ASSUME_TIME64_SYSCALLS */ ++#endif + return r; + } + #if __TIMESIZE != 64 +@@ -80,7 +94,7 @@ __recvmmsg (int fd, struct mmsghdr *vmessages, unsigned int vlen, int flags, + ts64 = valid_timespec_to_timespec64 (*timeout); + pts64 = &ts64; + } +- int r = __recvmmsg64 (fd, vmessages, vlen, flags, pts64); ++ int r = recvmmsg_syscall (fd, vmessages, vlen, flags, pts64); + if (r >= 0 && timeout != NULL) + /* The remanining timeout will be always less the input TIMEOUT. */ + *timeout = valid_timespec64_to_timespec (ts64); +diff --git a/sysdeps/unix/sysv/linux/recvmsg.c b/sysdeps/unix/sysv/linux/recvmsg.c +index 07212f7c86..c4b4704fd6 100644 +--- a/sysdeps/unix/sysv/linux/recvmsg.c ++++ b/sysdeps/unix/sysv/linux/recvmsg.c +@@ -20,29 +20,41 @@ + #include + #include + ++static int ++__recvmsg_syscall (int fd, struct msghdr *msg, int flags) ++{ ++#ifdef __ASSUME_RECVMSG_SYSCALL ++ return SYSCALL_CANCEL (recvmsg, fd, msg, flags); ++#else ++ return SOCKETCALL_CANCEL (recvmsg, fd, msg, flags); ++#endif ++} ++ + ssize_t +-__libc_recvmsg (int fd, struct msghdr *msg, int flags) ++__libc_recvmsg64 (int fd, struct msghdr *msg, int flags) + { + ssize_t r; +-#ifndef __ASSUME_TIME64_SYSCALLS ++#if __TIMESIZE != 64 + socklen_t orig_controllen = msg != NULL ? msg->msg_controllen : 0; + #endif + +-#ifdef __ASSUME_RECVMSG_SYSCALL +- r = SYSCALL_CANCEL (recvmsg, fd, msg, flags); +-#else +- r = SOCKETCALL_CANCEL (recvmsg, fd, msg, flags); +-#endif ++ r = __recvmsg_syscall (fd, msg, flags); + +-#ifndef __ASSUME_TIME64_SYSCALLS ++#if __TIMESIZE != 64 + if (r >= 0 && orig_controllen != 0) + __convert_scm_timestamps (msg, orig_controllen); + #endif + + return r; + } +-weak_alias (__libc_recvmsg, recvmsg) +-weak_alias (__libc_recvmsg, __recvmsg) + #if __TIMESIZE != 64 +-weak_alias (__recvmsg, __recvmsg64) ++weak_alias (__libc_recvmsg64, __recvmsg64) ++ ++ssize_t ++__libc_recvmsg (int fd, struct msghdr *msg, int flags) ++{ ++ return __recvmsg_syscall (fd, msg, flags); ++} + #endif ++weak_alias (__libc_recvmsg, recvmsg) ++weak_alias (__libc_recvmsg, __recvmsg) +diff --git a/sysdeps/unix/sysv/linux/tst-socket-timestamp-compat-time64.c b/sysdeps/unix/sysv/linux/tst-socket-timestamp-compat-time64.c +new file mode 100644 +index 0000000000..96a0bef0bf +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-socket-timestamp-compat-time64.c +@@ -0,0 +1 @@ ++#include "tst-socket-timestamp-compat.c" +diff --git a/sysdeps/unix/sysv/linux/tst-socket-timestamp-compat.c b/sysdeps/unix/sysv/linux/tst-socket-timestamp-compat.c +new file mode 100644 +index 0000000000..de261dae5a +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-socket-timestamp-compat.c +@@ -0,0 +1,265 @@ ++/* Check recvmsg/recvmmsg 64-bit timestamp support. ++ Copyright (C) 2022 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* AF_INET socket and address used to receive data. */ ++static int srv; ++static struct sockaddr_in srv_addr; ++ ++static int ++do_sendto (const struct sockaddr_in *addr, int payload) ++{ ++ int s = xsocket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); ++ xconnect (s, (const struct sockaddr *) addr, sizeof (*addr)); ++ ++ xsendto (s, &payload, sizeof (payload), 0, (const struct sockaddr *) addr, ++ sizeof (*addr)); ++ ++ xclose (s); ++ ++ return 0; ++} ++ ++static void ++do_recvmsg_ancillary (bool use_multi_call, struct mmsghdr *mmhdr, ++ void *msgbuf, size_t msgbuflen, int exp_payload) ++{ ++ int payload; ++ struct iovec iov = ++ { ++ .iov_base = &payload, ++ .iov_len = sizeof (payload) ++ }; ++ mmhdr->msg_hdr.msg_name = NULL; ++ mmhdr->msg_hdr.msg_iov = &iov; ++ mmhdr->msg_hdr.msg_iovlen = 1; ++ mmhdr->msg_hdr.msg_control = msgbuf; ++ mmhdr->msg_hdr.msg_controllen = msgbuflen; ++ ++ int r; ++ if (use_multi_call) ++ { ++ r = recvmmsg (srv, mmhdr, 1, 0, NULL); ++ if (r >= 0) ++ r = mmhdr->msg_len; ++ } ++ else ++ r = recvmsg (srv, &mmhdr->msg_hdr, 0); ++ TEST_COMPARE (r, sizeof (int)); ++ TEST_COMPARE (payload, exp_payload); ++} ++ ++/* Check if recvmsg create the additional 64 bit timestamp if only 32 bit ++ is enabled for 64 bit recvmsg symbol. */ ++static void ++do_test_large_buffer (bool mc) ++{ ++ struct mmsghdr mmhdr = { 0 }; ++ /* It should be large enought for either timeval/timespec and the ++ 64 time type as well. */ ++ ++ union ++ { ++ struct cmsghdr cmsghdr; ++ char msgbuf[512]; ++ } control; ++ ++ /* Enable 32 bit timeval precision and check if no 64 bit timeval stamp ++ is created. */ ++ { ++ int r = setsockopt (srv, SOL_SOCKET, SO_TIMESTAMP_OLD, &(int){1}, ++ sizeof (int)); ++ TEST_VERIFY_EXIT (r != -1); ++ ++ do_sendto (&srv_addr, 42); ++ do_recvmsg_ancillary (mc, &mmhdr, &control, sizeof control, 42); ++ ++ bool found_timestamp = false; ++ for (struct cmsghdr *cmsg = CMSG_FIRSTHDR (&mmhdr.msg_hdr); ++ cmsg != NULL; ++ cmsg = CMSG_NXTHDR (&mmhdr.msg_hdr, cmsg)) ++ { ++ if (cmsg->cmsg_level != SOL_SOCKET) ++ continue; ++ ++ if (sizeof (time_t) > 4 && cmsg->cmsg_type == SO_TIMESTAMP_NEW) ++ found_timestamp = true; ++ else ++ TEST_VERIFY (cmsg->cmsg_type != SO_TIMESTAMP_NEW); ++ } ++ ++ TEST_COMPARE (found_timestamp, sizeof (time_t) > 4); ++ } ++ ++ /* Same as before, but for timespec. */ ++ { ++ int r = setsockopt (srv, SOL_SOCKET, SO_TIMESTAMPNS_OLD, &(int){1}, ++ sizeof (int)); ++ TEST_VERIFY_EXIT (r != -1); ++ ++ do_sendto (&srv_addr, 42); ++ do_recvmsg_ancillary (mc, &mmhdr, &control, sizeof control, 42); ++ ++ bool found_timestamp = false; ++ for (struct cmsghdr *cmsg = CMSG_FIRSTHDR (&mmhdr.msg_hdr); ++ cmsg != NULL; ++ cmsg = CMSG_NXTHDR (&mmhdr.msg_hdr, cmsg)) ++ { ++ if (cmsg->cmsg_level != SOL_SOCKET) ++ continue; ++ ++ if (sizeof (time_t) > 4 && cmsg->cmsg_type == SO_TIMESTAMPNS_NEW) ++ found_timestamp = true; ++ else ++ TEST_VERIFY (cmsg->cmsg_type != SO_TIMESTAMPNS_NEW); ++ } ++ ++ TEST_COMPARE (found_timestamp, sizeof (time_t) > 4); ++ } ++} ++ ++/* Check if recvmsg does not create the additional 64 bit timestamp if ++ only 32 bit timestamp is enabled if the ancillary buffer is not large ++ enought. Also checks if MSG_CTRUNC is set iff for 64 bit recvmsg ++ symbol. */ ++static void ++do_test_small_buffer (bool mc) ++{ ++ struct mmsghdr mmhdr = { 0 }; ++ ++ /* Enable 32 bit timeval precision and check if no 64 bit timeval stamp ++ is created. */ ++ { ++ int r = setsockopt (srv, SOL_SOCKET, SO_TIMESTAMP_OLD, &(int){1}, ++ sizeof (int)); ++ TEST_VERIFY_EXIT (r != -1); ++ ++ union ++ { ++ struct cmsghdr cmsghdr; ++ char msgbuf[CMSG_SPACE (sizeof (struct timeval))]; ++ } control; ++ ++ do_sendto (&srv_addr, 42); ++ do_recvmsg_ancillary (mc, &mmhdr, &control, sizeof control, 42); ++ ++ bool found_timestamp = false; ++ for (struct cmsghdr *cmsg = CMSG_FIRSTHDR (&mmhdr.msg_hdr); ++ cmsg != NULL; ++ cmsg = CMSG_NXTHDR (&mmhdr.msg_hdr, cmsg)) ++ { ++ if (cmsg->cmsg_level != SOL_SOCKET) ++ continue; ++ ++ if (sizeof (time_t) > 4 && cmsg->cmsg_type == SO_TIMESTAMP_NEW) ++ found_timestamp = true; ++ else ++ TEST_VERIFY (cmsg->cmsg_type != SO_TIMESTAMP_NEW); ++ } ++ ++ if (sizeof (time_t) > 4) ++ { ++ TEST_VERIFY ((mmhdr.msg_hdr.msg_flags & MSG_CTRUNC)); ++ TEST_COMPARE (found_timestamp, 0); ++ } ++ else ++ { ++ TEST_VERIFY (!(mmhdr.msg_hdr.msg_flags & MSG_CTRUNC)); ++ TEST_COMPARE (found_timestamp, 0); ++ } ++ } ++ ++ /* Same as before, but for timespec. */ ++ { ++ int r = setsockopt (srv, SOL_SOCKET, SO_TIMESTAMPNS_OLD, &(int){1}, ++ sizeof (int)); ++ TEST_VERIFY_EXIT (r != -1); ++ ++ union ++ { ++ struct cmsghdr cmsghdr; ++ char msgbuf[CMSG_SPACE (sizeof (struct timespec))]; ++ } control; ++ ++ do_sendto (&srv_addr, 42); ++ do_recvmsg_ancillary (mc, &mmhdr, &control, sizeof control, 42); ++ ++ bool found_timestamp = false; ++ for (struct cmsghdr *cmsg = CMSG_FIRSTHDR (&mmhdr.msg_hdr); ++ cmsg != NULL; ++ cmsg = CMSG_NXTHDR (&mmhdr.msg_hdr, cmsg)) ++ { ++ if (cmsg->cmsg_level != SOL_SOCKET) ++ continue; ++ ++ if (sizeof (time_t) > 4 && cmsg->cmsg_type == SO_TIMESTAMPNS_NEW) ++ found_timestamp = true; ++ else ++ TEST_VERIFY (cmsg->cmsg_type != SO_TIMESTAMPNS_NEW); ++ } ++ ++ if (sizeof (time_t) > 4) ++ { ++ TEST_VERIFY ((mmhdr.msg_hdr.msg_flags & MSG_CTRUNC)); ++ TEST_COMPARE (found_timestamp, 0); ++ } ++ else ++ { ++ TEST_VERIFY ((mmhdr.msg_hdr.msg_flags & MSG_CTRUNC) == 0); ++ TEST_COMPARE (found_timestamp, 0); ++ } ++ } ++} ++ ++static int ++do_test (void) ++{ ++ /* This test only make sense for ABIs that support 32 bit time_t socket ++ timestampss. */ ++ if (sizeof (time_t) > 4 && __WORDSIZE == 64) ++ return 0; ++ ++ srv = xsocket (AF_INET, SOCK_DGRAM, 0); ++ srv_addr = (struct sockaddr_in) { ++ .sin_family = AF_INET, ++ .sin_addr = {.s_addr = htonl (INADDR_LOOPBACK) }, ++ }; ++ xbind (srv, (struct sockaddr *) &srv_addr, sizeof (srv_addr)); ++ { ++ socklen_t sa_len = sizeof (srv_addr); ++ xgetsockname (srv, (struct sockaddr *) &srv_addr, &sa_len); ++ TEST_VERIFY (sa_len == sizeof (srv_addr)); ++ } ++ ++ /* Check recvmsg; */ ++ do_test_large_buffer (false); ++ do_test_small_buffer (false); ++ /* Check recvmmsg. */ ++ do_test_large_buffer (true); ++ do_test_small_buffer (true); ++ ++ return 0; ++} ++ ++#include +-- +2.27.0 + diff --git a/Linux-Simplify-__opensock-and-fix-race-condition-BZ-.patch b/Linux-Simplify-__opensock-and-fix-race-condition-BZ-.patch new file mode 100644 index 0000000000000000000000000000000000000000..b7cbeef7cd7b54c930ca24e7a6a5d131def37f9f --- /dev/null +++ b/Linux-Simplify-__opensock-and-fix-race-condition-BZ-.patch @@ -0,0 +1,241 @@ +From 5bf07e1b3a74232bfb8332275110be1a5da50f83 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Tue, 28 Sep 2021 18:55:49 +0200 +Subject: [PATCH] Linux: Simplify __opensock and fix race condition [BZ #28353] + +AF_NETLINK support is not quite optional on modern Linux systems +anymore, so it is likely that the first attempt will always succeed. +Consequently, there is no need to cache the result. Keep AF_UNIX +and the Internet address families as a fallback, for the rare case +that AF_NETLINK is missing. The other address families previously +probed are totally obsolete be now, so remove them. + +Use this simplified version as the generic implementation, disabling +Netlink support as needed. +--- + socket/opensock.c | 65 +++++--------- + sysdeps/unix/sysv/linux/opensock.c | 114 ------------------------ + sysdeps/unix/sysv/linux/s390/opensock.c | 2 - + 3 files changed, 22 insertions(+), 159 deletions(-) + delete mode 100644 sysdeps/unix/sysv/linux/opensock.c + delete mode 100644 sysdeps/unix/sysv/linux/s390/opensock.c + +diff --git a/socket/opensock.c b/socket/opensock.c +index 37148d4743..ff94d27a61 100644 +--- a/socket/opensock.c ++++ b/socket/opensock.c +@@ -1,4 +1,5 @@ +-/* Copyright (C) 1999-2021 Free Software Foundation, Inc. ++/* Create socket with an unspecified address family for use with ioctl. ++ Copyright (C) 1999-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 +@@ -15,56 +16,34 @@ + License along with the GNU C Library; if not, see + . */ + +-#include ++#include + #include +-#include + + /* Return a socket of any type. The socket can be used in subsequent + ioctl calls to talk to the kernel. */ + int + __opensock (void) + { +- /* Cache the last AF that worked, to avoid many redundant calls to +- socket(). */ +- static int sock_af = -1; +- int fd = -1; +- __libc_lock_define_initialized (static, lock); +- +- if (sock_af != -1) +- { +- fd = __socket (sock_af, SOCK_DGRAM, 0); +- if (fd != -1) +- return fd; +- } +- +- __libc_lock_lock (lock); +- +- if (sock_af != -1) +- fd = __socket (sock_af, SOCK_DGRAM, 0); +- +- if (fd == -1) +- { +-#ifdef AF_INET +- fd = __socket (sock_af = AF_INET, SOCK_DGRAM, 0); +-#endif +-#ifdef AF_INET6 +- if (fd < 0) +- fd = __socket (sock_af = AF_INET6, SOCK_DGRAM, 0); +-#endif +-#ifdef AF_IPX +- if (fd < 0) +- fd = __socket (sock_af = AF_IPX, SOCK_DGRAM, 0); +-#endif +-#ifdef AF_AX25 +- if (fd < 0) +- fd = __socket (sock_af = AF_AX25, SOCK_DGRAM, 0); +-#endif +-#ifdef AF_APPLETALK +- if (fd < 0) +- fd = __socket (sock_af = AF_APPLETALK, SOCK_DGRAM, 0); ++ /* SOCK_DGRAM is supported by all address families. (Netlink does ++ not support SOCK_STREAM.) */ ++ int type = SOCK_DGRAM | SOCK_CLOEXEC; ++ int fd; ++ ++#ifdef AF_NETLINK ++ fd = __socket (AF_NETLINK, type, 0); ++ if (fd >= 0) ++ return fd; + #endif +- } + +- __libc_lock_unlock (lock); ++ fd = __socket (AF_UNIX, type, 0); ++ if (fd >= 0) ++ return fd; ++ fd = __socket (AF_INET, type, 0); ++ if (fd >= 0) ++ return fd; ++ fd = __socket (AF_INET6, type, 0); ++ if (fd >= 0) ++ return fd; ++ __set_errno (ENOENT); + return fd; + } +diff --git a/sysdeps/unix/sysv/linux/opensock.c b/sysdeps/unix/sysv/linux/opensock.c +deleted file mode 100644 +index e87d6e58b0..0000000000 +--- a/sysdeps/unix/sysv/linux/opensock.c ++++ /dev/null +@@ -1,114 +0,0 @@ +-/* Copyright (C) 1999-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 +- . */ +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-/* Return a socket of any type. The socket can be used in subsequent +- ioctl calls to talk to the kernel. */ +-int +-__opensock (void) +-{ +- static int last_family; /* Available socket family we will use. */ +- static int last_type; +- static const struct +- { +- int family; +- const char procname[15]; +- } afs[] = +- { +- { AF_UNIX, "net/unix" }, +- { AF_INET, "" }, +- { AF_INET6, "net/if_inet6" }, +- { AF_AX25, "net/ax25" }, +- { AF_NETROM, "net/nr" }, +- { AF_ROSE, "net/rose" }, +- { AF_IPX, "net/ipx" }, +- { AF_APPLETALK, "net/appletalk" }, +- { AF_ECONET, "sys/net/econet" }, +- { AF_ASH, "sys/net/ash" }, +- { AF_X25, "net/x25" }, +-#ifdef NEED_AF_IUCV +- { AF_IUCV, "net/iucv" } +-#endif +- }; +-#define nafs (sizeof (afs) / sizeof (afs[0])) +- char fname[sizeof "/proc/" + 14]; +- int result; +- int has_proc; +- size_t cnt; +- +- /* We already know which family to use from the last call. Use it +- again. */ +- if (last_family != 0) +- { +- assert (last_type != 0); +- +- result = __socket (last_family, last_type | SOCK_CLOEXEC, 0); +- if (result != -1 || errno != EAFNOSUPPORT) +- /* Maybe the socket type isn't supported anymore (module is +- unloaded). In this case again try to find the type. */ +- return result; +- +- /* Reset the values. They seem not valid anymore. */ +- last_family = 0; +- last_type = 0; +- } +- +- /* Check whether the /proc filesystem is available. */ +- has_proc = __access ("/proc/net", R_OK) != -1; +- strcpy (fname, "/proc/"); +- +- /* Iterate over the interface families and find one which is +- available. */ +- for (cnt = 0; cnt < nafs; ++cnt) +- { +- int type = SOCK_DGRAM; +- +- if (has_proc && afs[cnt].procname[0] != '\0') +- { +- strcpy (fname + 6, afs[cnt].procname); +- if (__access (fname, R_OK) == -1) +- /* The /proc entry is not available. I.e., we cannot +- create a socket of this type (without loading the +- module). Don't look for it since this might trigger +- loading the module. */ +- continue; +- } +- +- if (afs[cnt].family == AF_NETROM || afs[cnt].family == AF_X25) +- type = SOCK_SEQPACKET; +- +- result = __socket (afs[cnt].family, type | SOCK_CLOEXEC, 0); +- if (result != -1) +- { +- /* Found an available family. */ +- last_type = type; +- last_family = afs[cnt].family; +- return result; +- } +- } +- +- /* None of the protocol families is available. It is unclear what kind +- of error is returned. ENOENT seems like a reasonable choice. */ +- __set_errno (ENOENT); +- return -1; +-} +diff --git a/sysdeps/unix/sysv/linux/s390/opensock.c b/sysdeps/unix/sysv/linux/s390/opensock.c +deleted file mode 100644 +index f099d651ff..0000000000 +--- a/sysdeps/unix/sysv/linux/s390/opensock.c ++++ /dev/null +@@ -1,2 +0,0 @@ +-#define NEED_AF_IUCV 1 +-#include "../opensock.c" +-- +2.27.0 + diff --git a/Remove-sysdeps-tls-macros.h.patch b/Remove-sysdeps-tls-macros.h.patch new file mode 100644 index 0000000000000000000000000000000000000000..82561b7860cdf06af01c8368d7528ecf6048f3d1 --- /dev/null +++ b/Remove-sysdeps-tls-macros.h.patch @@ -0,0 +1,1810 @@ +From 710ba420fd417a4a82e0ad2e998e5f3b972cb503 Mon Sep 17 00:00:00 2001 +From: Fangrui Song +Date: Wed, 18 Aug 2021 09:15:20 -0700 +Subject: [PATCH] Remove sysdeps/*/tls-macros.h + +They provide TLS_GD/TLS_LD/TLS_IE/TLS_IE macros for TLS testing. Now +that we have migrated to __thread and tls_model attributes, these macros +are unused and the tls-macros.h files can retire. + +Reviewed-by: Szabolcs Nagy +--- + benchtests/strcoll-inputs/filelist#en_US.UTF-8 | 22 ---- + sysdeps/aarch64/tls-macros.h | 51 --------- + sysdeps/alpha/tls-macros.h | 25 ----- + sysdeps/arc/tls-macros.h | 47 -------- + sysdeps/arm/tls-macros.h | 72 ------------- + sysdeps/csky/abiv2/tls-macros.h | 55 ---------- + sysdeps/generic/tls-macros.h | 12 --- + sysdeps/hppa/tls-macros.h | 114 -------------------- + sysdeps/i386/tls-macros.h | 47 -------- + sysdeps/ia64/tls-macros.h | 66 ------------ + sysdeps/m68k/tls-macros.h | 68 ------------ + sysdeps/microblaze/tls-macros.h | 46 -------- + sysdeps/mips/tls-macros.h | 130 ---------------------- + sysdeps/nios2/tls-macros.h | 46 -------- + sysdeps/powerpc/powerpc32/tls-macros.h | 49 --------- + sysdeps/powerpc/powerpc64/tls-macros.h | 42 -------- + sysdeps/powerpc/tls-macros.h | 3 - + sysdeps/riscv/tls-macros.h | 47 -------- + sysdeps/s390/s390-32/tls-macros.h | 106 ------------------ + sysdeps/s390/s390-64/tls-macros.h | 90 ---------------- + sysdeps/sh/tls-macros.h | 143 ------------------------- + sysdeps/sparc/sparc32/tls-macros.h | 66 ------------ + sysdeps/sparc/sparc64/tls-macros.h | 65 ----------- + sysdeps/x86_64/tls-macros.h | 39 ------- + 24 files changed, 1451 deletions(-) + delete mode 100644 sysdeps/aarch64/tls-macros.h + delete mode 100644 sysdeps/alpha/tls-macros.h + delete mode 100644 sysdeps/arc/tls-macros.h + delete mode 100644 sysdeps/arm/tls-macros.h + delete mode 100644 sysdeps/csky/abiv2/tls-macros.h + delete mode 100644 sysdeps/generic/tls-macros.h + delete mode 100644 sysdeps/hppa/tls-macros.h + delete mode 100644 sysdeps/i386/tls-macros.h + delete mode 100644 sysdeps/ia64/tls-macros.h + delete mode 100644 sysdeps/m68k/tls-macros.h + delete mode 100644 sysdeps/microblaze/tls-macros.h + delete mode 100644 sysdeps/mips/tls-macros.h + delete mode 100644 sysdeps/nios2/tls-macros.h + delete mode 100644 sysdeps/powerpc/powerpc32/tls-macros.h + delete mode 100644 sysdeps/powerpc/powerpc64/tls-macros.h + delete mode 100644 sysdeps/powerpc/tls-macros.h + delete mode 100644 sysdeps/riscv/tls-macros.h + delete mode 100644 sysdeps/s390/s390-32/tls-macros.h + delete mode 100644 sysdeps/s390/s390-64/tls-macros.h + delete mode 100644 sysdeps/sh/tls-macros.h + delete mode 100644 sysdeps/sparc/sparc32/tls-macros.h + delete mode 100644 sysdeps/sparc/sparc64/tls-macros.h + delete mode 100644 sysdeps/x86_64/tls-macros.h + +diff --git a/benchtests/strcoll-inputs/filelist#en_US.UTF-8 b/benchtests/strcoll-inputs/filelist#en_US.UTF-8 +index 43eb9ef..197700e 100644 +--- a/benchtests/strcoll-inputs/filelist#en_US.UTF-8 ++++ b/benchtests/strcoll-inputs/filelist#en_US.UTF-8 +@@ -3195,7 +3195,6 @@ Implies + submul_1.S + sysdep.h + add_n.S +-tls-macros.h + libc-tls.c + sub_n.S + libgcc-compat.c +@@ -3443,7 +3442,6 @@ libresolv.abilist + thread_state.h + pty-private.h + ldconfig.h +-tls-macros.h + fd_to_filename.h + not-cancel.h + safe-fatal.h +@@ -3605,7 +3603,6 @@ start.S + tst-mode-switch-3.c + addmul_1.S + add_n.S +-tls-macros.h + libc-tls.c + sub_n.S + strcmp.S +@@ -3921,7 +3918,6 @@ addmul_1.S + pthread_spin_trylock.S + add_n.S + e_sqrt.c +-tls-macros.h + sub_n.S + strcmp.S + strlen.S +@@ -4138,7 +4134,6 @@ addmul_1.S + pthread_spin_trylock.S + add_n.S + rtld-memset.c +-tls-macros.h + sub_n.S + strcmp.S + strlen.S +@@ -4651,7 +4646,6 @@ addmul_1.S + sysdep.h + strlen.c + add_n.S +-tls-macros.h + sub_n.S + i786 + Implies +@@ -4712,7 +4706,6 @@ Makefile + start.S + libm-test-ulps + sysdep.h +-tls-macros.h + libc-tls.c + tst-audit.h + dl-machine.h +@@ -5071,7 +5064,6 @@ addmul_1.S + sysdep.h + add_n.S + wcschr.S +-tls-macros.h + sub_n.S + tst-quad2.c + strcmp.S +@@ -6337,7 +6329,6 @@ Makefile + start.S + libm-test-ulps + sysdep.h +-tls-macros.h + libc-tls.c + strlen.S + tst-audit.h +@@ -6447,7 +6438,6 @@ strstr.c + string-endian.h + memcmp.c + sysdep.h +-tls-macros.h + tst-audit.h + dl-machine.h + dl-tls.h +@@ -6581,7 +6571,6 @@ Makefile + start.S + libm-test-ulps + sysdep.h +-tls-macros.h + libc-tls.c + strcmp.S + strrchr.S +@@ -7004,7 +6993,6 @@ addmul_1.S + Implies + sysdep.h + rtld-memset.c +-tls-macros.h + strcmp.S + strlen.S + tst-audit.h +@@ -7124,7 +7112,6 @@ wcschr.c + Makefile + ffs.c + sysdep.h +-tls-macros.h + test-arithf.c + nofpu + atomic-feupdateenv.c +@@ -7386,7 +7373,6 @@ gprrest0.S + sysdep.h + add_n.S + rtld-memset.c +-tls-macros.h + sub_n.S + strcmp.S + strlen.S +@@ -7969,7 +7955,6 @@ memcmp.S + Makefile + start.S + sysdep.h +-tls-macros.h + libc-tls.c + strcmp.S + sched_cpucount.c +@@ -8197,7 +8182,6 @@ start.S + addmul_1.S + nscd-types.h + add_n.S +-tls-macros.h + libc-tls.c + sub_n.S + divqu.S +@@ -8318,7 +8302,6 @@ Makefile + ffs.c + start.S + sysdep.h +-tls-macros.h + libc-tls.c + tst-audit.h + wcpcpy.c +@@ -8628,7 +8611,6 @@ Makefile + start.S + sysdep.h + add_n.S +-tls-macros.h + sub_n.S + strcmp.S + tst-audit.h +@@ -8690,7 +8672,6 @@ start.S + addmul_1.S + sysdep.h + add_n.S +-tls-macros.h + sub_n.S + strcmp.S + tst-audit.h +@@ -8796,7 +8777,6 @@ ftestexcept.c + rt-aeabi_unwind_cpp_pr1.c + sysdep.h + add_n.S +-tls-macros.h + libc-tls.c + sub_n.S + strlen.S +@@ -8879,7 +8859,6 @@ Makefile + start.S + libm-test-ulps + sysdep.h +-tls-macros.h + libc-tls.c + tst-audit.h + dl-machine.h +@@ -12064,7 +12043,6 @@ nodelmod4.c + dl-fini.c + unload2dep.c + unload8.c +-tls-macros.h + unload4.c + tst-array5.exp + unload4mod2.c +diff --git a/sysdeps/aarch64/tls-macros.h b/sysdeps/aarch64/tls-macros.h +deleted file mode 100644 +index 33883dc..0000000 +--- a/sysdeps/aarch64/tls-macros.h ++++ /dev/null +@@ -1,51 +0,0 @@ +-/* Copyright (C) 2009-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 +- . */ +- +-#define TLS_LD(x) TLS_GD(x) +- +-#define TLS_GD(x) \ +- ({ register unsigned long __result asm ("x0"); \ +- asm ("adrp %0, :tlsgd:" #x "; " \ +- "add %0, %0, #:tlsgd_lo12:" #x "; " \ +- "bl __tls_get_addr;" \ +- "nop" \ +- : "=r" (__result) \ +- : \ +- : "x1", "x2", "x3", "x4", "x5", "x6", \ +- "x7", "x8", "x9", "x10", "x11", "x12", \ +- "x13", "x14", "x15", "x16", "x17", "x18", \ +- "x30", "memory", "cc"); \ +- (int *) (__result); }) +- +-#define TLS_IE(x) \ +- ({ register unsigned long __result asm ("x0"); \ +- register unsigned long __t; \ +- asm ("mrs %1, tpidr_el0; " \ +- "adrp %0, :gottprel:" #x "; " \ +- "ldr %0, [%0, #:gottprel_lo12:" #x "]; " \ +- "add %0, %0, %1" \ +- : "=r" (__result), "=r" (__t)); \ +- (int *) (__result); }) +- +-#define TLS_LE(x) \ +- ({ register unsigned long __result asm ("x0"); \ +- asm ("mrs %0, tpidr_el0; " \ +- "add %0, %0, :tprel_hi12:" #x "; " \ +- "add %0, %0, :tprel_lo12_nc:" #x \ +- : "=r" (__result)); \ +- (int *) (__result); }) +diff --git a/sysdeps/alpha/tls-macros.h b/sysdeps/alpha/tls-macros.h +deleted file mode 100644 +index 00489c2..0000000 +--- a/sysdeps/alpha/tls-macros.h ++++ /dev/null +@@ -1,25 +0,0 @@ +-/* Macros to support TLS testing in times of missing compiler support. */ +- +-extern void *__tls_get_addr (void *); +- +-# define TLS_GD(x) \ +- ({ register void *__gp asm ("$29"); void *__result; \ +- asm ("lda %0, " #x "($gp) !tlsgd" : "=r" (__result) : "r"(__gp)); \ +- __tls_get_addr (__result); }) +- +-# define TLS_LD(x) \ +- ({ register void *__gp asm ("$29"); void *__result; \ +- asm ("lda %0, " #x "($gp) !tlsldm" : "=r" (__result) : "r"(__gp)); \ +- __result = __tls_get_addr (__result); \ +- asm ("lda %0, " #x "(%0) !dtprel" : "+r" (__result)); \ +- __result; }) +- +-# define TLS_IE(x) \ +- ({ register void *__gp asm ("$29"); long ofs; \ +- asm ("ldq %0, " #x "($gp) !gottprel" : "=r"(ofs) : "r"(__gp)); \ +- __builtin_thread_pointer () + ofs; }) +- +-# define TLS_LE(x) \ +- ({ void *__result = __builtin_thread_pointer (); \ +- asm ("lda %0, " #x "(%0) !tprel" : "+r" (__result)); \ +- __result; }) +diff --git a/sysdeps/arc/tls-macros.h b/sysdeps/arc/tls-macros.h +deleted file mode 100644 +index b0003d8..0000000 +--- a/sysdeps/arc/tls-macros.h ++++ /dev/null +@@ -1,47 +0,0 @@ +-/* Macros to support TLS testing in times of missing compiler support. ARC version. +- Copyright (C) 2020-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 +- . */ +- +- +-/* For now. */ +-#define TLS_LD(x) TLS_IE(x) +- +-#define TLS_GD(x) \ +- ({ void *__result; \ +- __asm__ ("add r0, pcl, @" #x "@tlsgd \n" \ +- ".tls_gd_ld " #x "`bl __tls_get_addr@plt \n" \ +- "mov %0, r0 \n" \ +- : "=&r" (__result) \ +- ::"r0","r1","r2","r3","r4","r5","r6","r7", \ +- "r8","r9","r10","r11","r12"); \ +- __result; }) +- +-#define TLS_LE(x) \ +- ({ void *__result; \ +- void *tp = __builtin_thread_pointer (); \ +- __asm__ ("add %0, %1, @" #x "@tpoff \n" \ +- : "=r" (__result) : "r"(tp)); \ +- __result; }) +- +-#define TLS_IE(x) \ +- ({ void *__result; \ +- void *tp = __builtin_thread_pointer (); \ +- __asm__ ("ld %0, [pcl, @" #x "@tlsie] \n" \ +- "add %0, %1, %0 \n" \ +- : "=&r" (__result) : "r" (tp)); \ +- __result; }) +diff --git a/sysdeps/arm/tls-macros.h b/sysdeps/arm/tls-macros.h +deleted file mode 100644 +index 25cd849..0000000 +--- a/sysdeps/arm/tls-macros.h ++++ /dev/null +@@ -1,72 +0,0 @@ +-#include /* For ARCH_HAS_T2. */ +- +-#ifdef __thumb2__ +-# define ARM_PC_OFFSET "4" +-#else +-# define ARM_PC_OFFSET "8" +-#endif +- +-/* Returns the address of data containing ".word SYMBOL(RELOC)". */ +-#if defined (ARCH_HAS_T2) && !defined (PIC) +-# define GET_SPECIAL_RELOC(symbol, reloc) \ +- ({ \ +- int *__##symbol##_rodata; \ +- asm ("movw %0, #:lower16:1f\n" \ +- "movt %0, #:upper16:1f\n" \ +- ".pushsection .rodata.cst4, \"aM\", %%progbits, 4\n" \ +- ".balign 4\n" \ +- "1: .word " #symbol "(" #reloc ")\n" \ +- ".popsection" \ +- : "=r" (__##symbol##_rodata)); \ +- __##symbol##_rodata; \ +- }) +-#elif defined (ARCH_HAS_T2) && defined (PIC) && ARM_PCREL_MOVW_OK +-# define GET_SPECIAL_RELOC(symbol, reloc) \ +- ({ \ +- int *__##symbol##_rodata; \ +- asm ("movw %0, #:lower16:1f - 2f - " ARM_PC_OFFSET "\n" \ +- "movt %0, #:upper16:1f - 2f - " ARM_PC_OFFSET "\n" \ +- ".pushsection .rodata.cst4, \"aM\", %%progbits, 4\n" \ +- ".balign 4\n" \ +- "1: .word " #symbol "(" #reloc ")\n" \ +- ".popsection\n" \ +- "2: add %0, %0, pc" \ +- : "=r" (__##symbol##_rodata)); \ +- __##symbol##_rodata; \ +- }) +-#else +-# define GET_SPECIAL_RELOC(symbol, reloc) \ +- ({ \ +- int *__##symbol##_rodata; \ +- asm ("adr %0, 1f\n" \ +- "b 2f\n" \ +- ".balign 4\n" \ +- "1: .word " #symbol "(" #reloc ")\n" \ +- "2:" \ +- : "=r" (__##symbol##_rodata)); \ +- __##symbol##_rodata; \ +- }) +-#endif +- +-/* Returns the pointer value (SYMBOL(RELOC) + pc - PC_OFS). */ +-#define GET_SPECIAL_PCREL(symbol, reloc) \ +- ({ \ +- int *__##symbol##_rodata = GET_SPECIAL_RELOC (symbol, reloc); \ +- (void *) ((int) __##symbol##_rodata + *__##symbol##_rodata); \ +- }) +- +-#define TLS_LE(x) \ +- (__builtin_thread_pointer () + *GET_SPECIAL_RELOC (x, tpoff)) +- +-#define TLS_IE(x) \ +- ((int *) (__builtin_thread_pointer () \ +- + *(int *) GET_SPECIAL_PCREL (x, gottpoff))) +- +-extern void *__tls_get_addr (void *); +- +-#define TLS_LD(x) \ +- ((int *) (__tls_get_addr (GET_SPECIAL_PCREL (x, tlsldm)) \ +- + *GET_SPECIAL_RELOC (x, tlsldo))) +- +-#define TLS_GD(x) \ +- ((int *) __tls_get_addr (GET_SPECIAL_PCREL (x, tlsgd))) +diff --git a/sysdeps/csky/abiv2/tls-macros.h b/sysdeps/csky/abiv2/tls-macros.h +deleted file mode 100644 +index 57ed1e7..0000000 +--- a/sysdeps/csky/abiv2/tls-macros.h ++++ /dev/null +@@ -1,55 +0,0 @@ +-/* Macros for accessing thread-local storage. C-SKY ABIV2 version. +- Copyright (C) 2018-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 +- . */ +- +-# define TLS_LE(x) \ +- ({ int *__result; \ +- __asm__ ("lrw %0, " #x "@TPOFF\n\t" \ +- "add %0, tls, %0" \ +- : "=&r" (__result)); \ +- __result; }) +- +-# define TLS_IE(x) \ +- ({ int *__result; \ +- __asm__ ("grs a1, 1f\n" \ +- "1:\tlrw %0, " #x "@GOTTPOFF\n\t" \ +- "ldr.w %0, (a1, %0 << 0)\n\t" \ +- "add %0, tls, %0" \ +- : "=&r" (__result): : "a1"); \ +- __result; }) +- +-# define TLS_LD(x) \ +- ({ char *__result; \ +- int __offset; \ +- extern void *__tls_get_addr (void *); \ +- __asm__ ("grs a1, 1f\n" \ +- "1:\tlrw %0, " #x "@TLSLDM32;\n\t" \ +- "add %0, a1, %0" \ +- : "=r" (__result) : : "a1"); \ +- __result = (char *)__tls_get_addr (__result); \ +- __asm__ ("lrw %0, " #x "@TLSLDO32" \ +- : "=r" (__offset)); \ +- (int *) (__result + __offset); }) +- +-# define TLS_GD(x) \ +- ({ int *__result; \ +- extern void *__tls_get_addr (void *); \ +- __asm__ ("grs a1, 1f\n" \ +- "1:\tlrw %0, " #x "@TLSGD32\n\t" \ +- "add %0, a1, %0" \ +- : "=r" (__result) : : "a1"); \ +- (int *)__tls_get_addr (__result); }) +diff --git a/sysdeps/generic/tls-macros.h b/sysdeps/generic/tls-macros.h +deleted file mode 100644 +index 0a08f7c..0000000 +--- a/sysdeps/generic/tls-macros.h ++++ /dev/null +@@ -1,12 +0,0 @@ +-/* Macros to support TLS testing in times of missing compiler support. +- Stub version. +- +- These macros should yield int * expressions for the TLS symbol X +- accessed using the various TLS access models. Macros for some machines +- are defined in elf/tls-macros.h, but ports can instead provide this file. +- +-#define TLS_LE(x) +-#define TLS_IE(x) +-#define TLS_LD(x) +-#define TLS_GD(x) +-*/ +diff --git a/sysdeps/hppa/tls-macros.h b/sysdeps/hppa/tls-macros.h +deleted file mode 100644 +index 38edb1b..0000000 +--- a/sysdeps/hppa/tls-macros.h ++++ /dev/null +@@ -1,114 +0,0 @@ +-/* TLS Access Macros for HP PARISC Linux */ +- +-/* HPPA Local Exec TLS access. */ +-#define TLS_LE(x) \ +- ({ int * __result; \ +- unsigned long __tmp; \ +- asm ( \ +- " mfctl %%cr27, %1\n" \ +- " addil LR'" #x "-$tls_leoff$, %1\n" \ +- " ldo RR'" #x "-$tls_leoff$(%%r1), %0\n" \ +- : "=r" (__result), "=r" (__tmp) \ +- : \ +- : "r1" ); \ +- __result; \ +- }) +- +-/* HPPA Initial Exec TLS access. */ +-#ifdef PIC +-# define TLS_IE(x) \ +- ({ int * __result; \ +- unsigned long __tmp, __tmp2; \ +- asm ( \ +- " mfctl %%cr27, %1\n" \ +- " addil LT'" #x "-$tls_ieoff$, %%r19\n" \ +- " ldw RT'" #x "-$tls_ieoff$(%%r1), %2\n" \ +- " add %1, %2, %0\n" \ +- : "=r" (__result), "=r" (__tmp), "=r" (__tmp2) \ +- : \ +- : "r1" ); \ +- __result; \ +- }) +-#else +-# define TLS_IE(x) \ +- ({ int * __result; \ +- unsigned long __tmp, __tmp2; \ +- asm ( \ +- " mfctl %%cr27, %1\n" \ +- " addil LR'" #x "-$tls_ieoff$, %%r27\n" \ +- " ldw RR'" #x "-$tls_ieoff$(%%r1), %2\n" \ +- " add %1, %2, %0\n" \ +- : "=r" (__result), "=r" (__tmp), "=r" (__tmp2) \ +- : \ +- : "r1" ); \ +- __result; \ +- }) +-#endif +- +-#ifdef PIC +-/* HPPA Local Dynamic TLS access. */ +-# define TLS_LD(x) \ +- ({ int * __result; \ +- asm ( \ +- " copy %%r19, %%r4\n" \ +- " addil LT'" #x "-$tls_ldidx$, %%r19\n" \ +- " bl __tls_get_addr, %%r2\n" \ +- " ldo RT'" #x "-$tls_ldidx$(%%r1), %%r26\n" \ +- " addil LR'" #x "-$tls_dtpoff$, %%r28\n" \ +- " ldo RR'" #x "-$tls_dtpoff$(%%r1), %0\n" \ +- " copy %%r4, %%r19\n" \ +- : "=r" (__result) \ +- : \ +- : "r1", "r2", "r4", "r20", "r21", "r22", "r23", "r24", \ +- "r25", "r26", "r28", "r29", "r31" ); \ +- __result; \ +- }) +-#else +-# define TLS_LD(x) \ +- ({ int * __result; \ +- asm ( \ +- " addil LR'" #x "-$tls_ldidx$, %%r27\n" \ +- " bl __tls_get_addr, %%r2\n" \ +- " ldo RR'" #x "-$tls_ldidx$(%%r1), %%r26\n" \ +- " addil LR'" #x "-$tls_dtpoff$, %%r28\n" \ +- " ldo RR'" #x "-$tls_dtpoff$(%%r1), %0\n" \ +- : "=r" (__result) \ +- : \ +- : "r1", "r2", "r20", "r21", "r22", "r23", "r24", \ +- "r25", "r26", "r28", "r29", "r31" ); \ +- __result; \ +- }) +-#endif +- +-/* HPPA General Dynamic TLS access. */ +-#ifdef PIC +-# define TLS_GD(x) \ +- ({ int * __result; \ +- asm ( \ +- " copy %%r19, %%r4\n" \ +- " addil LT'" #x "-$tls_gdidx$, %%r19\n" \ +- " bl __tls_get_addr, %%r2\n" \ +- " ldo RT'" #x "-$tls_gdidx$(%%r1), %%r26\n" \ +- " copy %%r28, %0\n" \ +- " copy %%r4, %%r19\n" \ +- : "=r" (__result) \ +- : \ +- : "r1", "r2", "r4", "r20", "r21", "r22", "r23", "r24", \ +- "r25", "r26", "r28", "r29", "r31" ); \ +- __result; \ +- }) +-#else +-# define TLS_GD(x) \ +- ({ int * __result; \ +- asm ( \ +- " addil LR'" #x "-$tls_gdidx$, %%r27\n" \ +- " bl __tls_get_addr, %%r2\n" \ +- " ldo RR'" #x "-$tls_gdidx$(%%r1), %%r26\n" \ +- " copy %%r28, %0\n" \ +- : "=r" (__result) \ +- : \ +- : "r1", "r2", "r20", "r21", "r22", "r23", "r24", \ +- "r25", "r26", "r28", "r29", "r31" ); \ +- __result; \ +- }) +-#endif +diff --git a/sysdeps/i386/tls-macros.h b/sysdeps/i386/tls-macros.h +deleted file mode 100644 +index 9c1303d..0000000 +--- a/sysdeps/i386/tls-macros.h ++++ /dev/null +@@ -1,47 +0,0 @@ +-#define TLS_LE(x) \ +- ({ int *__l; \ +- asm ("movl %%gs:0,%0\n\t" \ +- "subl $" #x "@tpoff,%0" \ +- : "=r" (__l)); \ +- __l; }) +- +-#define TLS_IE(x) \ +- ({ int *__l, __b; \ +- asm ("call 1f\n\t" \ +- ".subsection 1\n" \ +- "1:\tmovl (%%esp), %%ebx\n\t" \ +- "ret\n\t" \ +- ".previous\n\t" \ +- "addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t" \ +- "movl %%gs:0,%0\n\t" \ +- "subl " #x "@gottpoff(%%ebx),%0" \ +- : "=r" (__l), "=&b" (__b)); \ +- __l; }) +- +-#define TLS_LD(x) \ +- ({ int *__l, __b, __c, __d; \ +- asm ("call 1f\n\t" \ +- ".subsection 1\n" \ +- "1:\tmovl (%%esp), %%ebx\n\t" \ +- "ret\n\t" \ +- ".previous\n\t" \ +- "addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t" \ +- "leal " #x "@tlsldm(%%ebx),%%eax\n\t" \ +- "call ___tls_get_addr@plt\n\t" \ +- "leal " #x "@dtpoff(%%eax), %%eax" \ +- : "=a" (__l), "=&b" (__b), "=&c" (__c), "=&d" (__d)); \ +- __l; }) +- +-#define TLS_GD(x) \ +- ({ int *__l, __b, __c, __d; \ +- asm ("call 1f\n\t" \ +- ".subsection 1\n" \ +- "1:\tmovl (%%esp), %%ebx\n\t" \ +- "ret\n\t" \ +- ".previous\n\t" \ +- "addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t" \ +- "leal " #x "@tlsgd(%%ebx),%%eax\n\t" \ +- "call ___tls_get_addr@plt\n\t" \ +- "nop" \ +- : "=a" (__l), "=&b" (__b), "=&c" (__c), "=&d" (__d)); \ +- __l; }) +diff --git a/sysdeps/ia64/tls-macros.h b/sysdeps/ia64/tls-macros.h +deleted file mode 100644 +index 13b216d..0000000 +--- a/sysdeps/ia64/tls-macros.h ++++ /dev/null +@@ -1,66 +0,0 @@ +-/* Macros to support TLS testing in times of missing compiler support. */ +- +-extern void *__tls_get_addr (void *); +- +-# define TLS_LE(x) \ +- ({ void *__l; \ +- asm ("mov r2=r13\n\t" \ +- ";;\n\t" \ +- "addl %0=@tprel(" #x "),r2\n\t" \ +- : "=r" (__l) : : "r2" ); __l; }) +- +-# define TLS_IE(x) \ +- ({ void *__l; \ +- register long __gp asm ("gp"); \ +- asm (";;\n\t" \ +- "addl r16=@ltoff(@tprel(" #x ")),gp\n\t" \ +- ";;\n\t" \ +- "ld8 r17=[r16]\n\t" \ +- ";;\n\t" \ +- "add %0=r13,r17\n\t" \ +- ";;\n\t" \ +- : "=r" (__l) : "r" (__gp) : "r16", "r17" ); __l; }) +- +-# define __TLS_CALL_CLOBBERS \ +- "r2", "r3", "r8", "r9", "r10", "r11", "r14", "r15", "r16", "r17", \ +- "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", \ +- "r27", "r28", "r29", "r30", "r31", \ +- "p6", "p7", "p8", "p9", "p10", "p11", "p12", "p13", "p14", "p15", \ +- "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \ +- "b6", "b7", \ +- "out0", "out1", "out2", "out3", "out4", "out5", "out6", "out7" +- +-# define TLS_LD(x) \ +- ({ void *__l; \ +- register long __gp asm ("gp"); \ +- asm (";;\n\t" \ +- "mov loc0=gp\n\t" \ +- "addl r16=@ltoff(@dtpmod(" #x ")),gp\n\t" \ +- "addl out1=@dtprel(" #x "),r0\n\t" \ +- ";;\n\t" \ +- "ld8 out0=[r16]\n\t" \ +- "br.call.sptk.many b0=__tls_get_addr" \ +- ";;\n\t" \ +- "mov gp=loc0\n\t" \ +- "mov %0=r8\n\t" \ +- ";;\n\t" \ +- : "=r" (__l) : "r" (__gp) : "loc0", __TLS_CALL_CLOBBERS); \ +- __l; }) +- +-# define TLS_GD(x) \ +- ({ void *__l; \ +- register long __gp asm ("gp"); \ +- asm (";;\n\t" \ +- "mov loc0=gp\n\t" \ +- "addl r16=@ltoff(@dtpmod(" #x ")),gp\n\t" \ +- "addl r17=@ltoff(@dtprel(" #x ")),gp\n\t" \ +- ";;\n\t" \ +- "ld8 out0=[r16]\n\t" \ +- "ld8 out1=[r17]\n\t" \ +- "br.call.sptk.many b0=__tls_get_addr" \ +- ";;\n\t" \ +- "mov gp=loc0\n\t" \ +- "mov %0=r8\n\t" \ +- ";;\n\t" \ +- : "=r" (__l) : "r" (__gp) : "loc0", __TLS_CALL_CLOBBERS); \ +- __l; }) +diff --git a/sysdeps/m68k/tls-macros.h b/sysdeps/m68k/tls-macros.h +deleted file mode 100644 +index 5fe1735..0000000 +--- a/sysdeps/m68k/tls-macros.h ++++ /dev/null +@@ -1,68 +0,0 @@ +-/* Macros for accessing thread-local storage. m68k version. +- Copyright (C) 2010-2021 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- Contributed by Maxim Kuvyrkov , 2010. +- +- 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 +- . */ +- +-#define TLS_GD(x) \ +- ({ \ +- void *__result; \ +- extern void *__tls_get_addr (void *); \ +- \ +- asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t" \ +- "lea (-6, %%pc, %0), %0\n\t" \ +- "lea " #x "@TLSGD(%0), %0" \ +- : "=&a" (__result)); \ +- (int *) __tls_get_addr (__result); }) +- +-#define TLS_LD(x) \ +- ({ \ +- char *__tp; \ +- int __offset; \ +- extern void *__tls_get_addr (void *); \ +- \ +- asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t" \ +- "lea (-6, %%pc, %0), %0\n\t" \ +- "lea " #x "@TLSLDM(%0), %0" \ +- : "=&a" (__tp)); \ +- __tp = (char *) __tls_get_addr (__tp); \ +- asm ("movel #" #x "@TLSLDO, %0" \ +- : "=a" (__offset)); \ +- (int *) (__tp + __offset); }) +- +-#define TLS_IE(x) \ +- ({ \ +- char *__tp; \ +- int __offset; \ +- extern void * __m68k_read_tp (void); \ +- \ +- __tp = (char *) __m68k_read_tp (); \ +- asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t" \ +- "lea (-6, %%pc, %0), %0\n\t" \ +- "movel " #x "@TLSIE(%0), %0" \ +- : "=&a" (__offset)); \ +- (int *) (__tp + __offset); }) +- +-#define TLS_LE(x) \ +- ({ \ +- char *__tp; \ +- int __offset; \ +- extern void * __m68k_read_tp (void); \ +- \ +- __tp = (char *) __m68k_read_tp (); \ +- asm ("movel #" #x "@TLSLE, %0" \ +- : "=a" (__offset)); \ +- (int *) (__tp + __offset); }) +diff --git a/sysdeps/microblaze/tls-macros.h b/sysdeps/microblaze/tls-macros.h +deleted file mode 100644 +index f7cd59d..0000000 +--- a/sysdeps/microblaze/tls-macros.h ++++ /dev/null +@@ -1,46 +0,0 @@ +-/* Copyright (C) 2009-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 +- . */ +- +-#define TLS_LD(x) \ +- ({ \ +- char *__result; \ +- int __offset; \ +- extern void *__tls_get_addr (void *); \ +- asm ("mfs r20,rpc \n" \ +- "addik r20,r20,_GLOBAL_OFFSET_TABLE_+8\n" \ +- "addik %0,r20," #x "@TLSLDM" \ +- : "=r" (__result)); \ +- __result = (char *) __tls_get_addr (__result); \ +- asm ("addik %0,r0,"#x"@TLSDTPREL" \ +- : "=r" (__offset)); \ +- (int *) (__result + __offset); }) +- +- +-#define TLS_GD(x) \ +- ({ \ +- int *__result; \ +- extern void *__tls_get_addr (void *); \ +- asm ("mfs r20,rpc\n" \ +- "addik r20,r20,_GLOBAL_OFFSET_TABLE_+8\n" \ +- "addik %0,r20," #x "@TLSGD" \ +- : "=r" (__result)); \ +- (int *) __tls_get_addr (__result); }) +- +-#define TLS_LE(x) TLS_LD(x) +- +-#define TLS_IE(x) TLS_GD(x) +diff --git a/sysdeps/mips/tls-macros.h b/sysdeps/mips/tls-macros.h +deleted file mode 100644 +index a6fdfbc..0000000 +--- a/sysdeps/mips/tls-macros.h ++++ /dev/null +@@ -1,130 +0,0 @@ +-/* Macros to support TLS testing in times of missing compiler support. */ +- +-#include +-#include +-#include +- +-#define __STRING2(X) __STRING(X) +-#define ADDU __STRING2(PTR_ADDU) +-#define ADDIU __STRING2(PTR_ADDIU) +-#define LW __STRING2(PTR_L) +- +-/* Load the GOT pointer, which may not be in $28 in a non-PIC +- (abicalls pic0) function. */ +-#ifndef __PIC__ +-# if _MIPS_SIM != _ABI64 +-# ifndef __mips16 +-# define LOAD_GP "move %[tmp], $28\n\tla $28, __gnu_local_gp\n\t" +-# else +-# define LOAD_GP \ +- "li %[tmp], %%hi(__gnu_local_gp)\n\t" \ +- "sll %[tmp], 16\n\t" \ +- "addiu %[tmp], %%lo(__gnu_local_gp)\n\t" +-# endif +-# else +-# define LOAD_GP "move %[tmp], $28\n\tdla $28, __gnu_local_gp\n\t" +-# endif +-# define UNLOAD_GP "\n\tmove $28, %[tmp]" +-#else +-/* MIPS16 (re)creates the GP value using PC-relative instructions. */ +-# ifdef __mips16 +-# define LOAD_GP \ +- "li %[tmp], %%hi(_gp_disp)\n\t" \ +- "addiu %0, $pc, %%lo(_gp_disp)\n\t" \ +- "sll %[tmp], 16\n\t" \ +- "addu %[tmp], %0\n\t" +-# else +-# define LOAD_GP +-# endif +-# define UNLOAD_GP +-#endif +- +-# if __mips_isa_rev >= 2 +-# define TLS_RDHWR "rdhwr\t%0,$29" +-# else +-# define TLS_RDHWR \ +- ".set push\n\t.set mips32r2\n\t" \ +- "rdhwr\t%0,$29\n\t.set pop" +-#endif +- +-#ifndef __mips16 +-# define TLS_GD(x) \ +- ({ void *__result, *__tmp; \ +- extern void *__tls_get_addr (void *); \ +- asm (LOAD_GP ADDIU " %0, $28, %%tlsgd(" #x ")" \ +- UNLOAD_GP \ +- : "=r" (__result), [tmp] "=&r" (__tmp)); \ +- (int *)__tls_get_addr (__result); }) +-# define TLS_LD(x) \ +- ({ void *__result, *__tmp; \ +- extern void *__tls_get_addr (void *); \ +- asm (LOAD_GP ADDIU " %0, $28, %%tlsldm(" #x ")" \ +- UNLOAD_GP \ +- : "=r" (__result), [tmp] "=&r" (__tmp)); \ +- __result = __tls_get_addr (__result); \ +- asm ("lui $3,%%dtprel_hi(" #x ")\n\t" \ +- "addiu $3,$3,%%dtprel_lo(" #x ")\n\t" \ +- ADDU " %0,%0,$3" \ +- : "+r" (__result) : : "$3"); \ +- __result; }) +-# define TLS_IE(x) \ +- ({ void *__result, *__tmp; \ +- asm (TLS_RDHWR \ +- : "=v" (__result)); \ +- asm (LOAD_GP LW " $3,%%gottprel(" #x ")($28)\n\t" \ +- ADDU " %0,%0,$3" \ +- UNLOAD_GP \ +- : "+r" (__result), [tmp] "=&r" (__tmp) \ +- : : "$3"); \ +- __result; }) +-# define TLS_LE(x) \ +- ({ void *__result; \ +- asm (TLS_RDHWR \ +- : "=v" (__result)); \ +- asm ("lui $3,%%tprel_hi(" #x ")\n\t" \ +- "addiu $3,$3,%%tprel_lo(" #x ")\n\t" \ +- ADDU " %0,%0,$3" \ +- : "+r" (__result) : : "$3"); \ +- __result; }) +- +-#else /* __mips16 */ +-/* MIPS16 version. */ +-# define TLS_GD(x) \ +- ({ void *__result, *__tmp; \ +- extern void *__tls_get_addr (void *); \ +- asm (LOAD_GP ADDIU " %1, %%tlsgd(" #x ")" \ +- "\n\tmove %0, %1" \ +- : "=d" (__result), [tmp] "=&d" (__tmp)); \ +- (int *) __tls_get_addr (__result); }) +-# define TLS_LD(x) \ +- ({ void *__result, *__tmp; \ +- extern void *__tls_get_addr (void *); \ +- asm (LOAD_GP ADDIU " %1, %%tlsldm(" #x ")" \ +- "\n\tmove %0, %1" \ +- : "=d" (__result), [tmp] "=&d" (__tmp)); \ +- __result = __tls_get_addr (__result); \ +- asm ("li $3,%%dtprel_hi(" #x ")\n\t" \ +- "sll $3,16\n\t" \ +- "addiu $3,%%dtprel_lo(" #x ")\n\t" \ +- ADDU " %0,%0,$3" \ +- : "+d" (__result) : : "$3"); \ +- __result; }) +-# define TLS_IE(x) \ +- ({ void *__result, *__tmp, *__tp; \ +- __tp = __builtin_thread_pointer (); \ +- asm (LOAD_GP LW " $3,%%gottprel(" #x ")(%1)\n\t" \ +- ADDU " %0,%[tp],$3" \ +- : "=&d" (__result), [tmp] "=&d" (__tmp) \ +- : [tp] "d" (__tp) : "$3"); \ +- __result; }) +-# define TLS_LE(x) \ +- ({ void *__result, *__tp; \ +- __tp = __builtin_thread_pointer (); \ +- asm ("li $3,%%tprel_hi(" #x ")\n\t" \ +- "sll $3,16\n\t" \ +- "addiu $3,%%tprel_lo(" #x ")\n\t" \ +- ADDU " %0,%[tp],$3" \ +- : "=d" (__result) : [tp] "d" (__tp) : "$3"); \ +- __result; }) +- +-#endif /* __mips16 */ +diff --git a/sysdeps/nios2/tls-macros.h b/sysdeps/nios2/tls-macros.h +deleted file mode 100644 +index 7029530..0000000 +--- a/sysdeps/nios2/tls-macros.h ++++ /dev/null +@@ -1,46 +0,0 @@ +-#define TLS_LE(x) \ +- ({ int *__result; \ +- asm ("addi %0, r23, %%tls_le(" #x ")" \ +- : "=r" (__result)); \ +- __result; }) +- +-#define TLS_IE(x) \ +- ({ int *__result; \ +- int __tmp; \ +- asm ("nextpc %0 ; " \ +- "1: movhi %1, %%hiadj(_gp_got - 1b) ; " \ +- "addi %1, %1, %%lo(_gp_got - 1b) ; " \ +- "add %0, %0, %1 ; " \ +- "ldw %1, %%tls_ie(" #x ")(%0) ; " \ +- "add %1, r23, %1" \ +- : "=&r" (__tmp), "=&r" (__result)); \ +- __result; }) +- +-#define TLS_LD(x) \ +- ({ char *__result; \ +- char *__result2; \ +- int *__result3; \ +- int __tmp; \ +- extern void *__tls_get_addr (void *); \ +- asm ("nextpc %0 ; " \ +- "1: movhi %1, %%hiadj(_gp_got - 1b) ; " \ +- "addi %1, %1, %%lo(_gp_got - 1b) ; " \ +- "add %0, %0, %1 ; " \ +- "addi %0, %0, %%tls_ldm(" #x ")" \ +- : "=r" (__result), "=r" (__tmp)); \ +- __result2 = (char *)__tls_get_addr (__result); \ +- asm ("addi %0, %1, %%tls_ldo(" #x ")" \ +- : "=r" (__result3) : "r" (__result2)); \ +- __result3; }) +- +-#define TLS_GD(x) \ +- ({ int *__result; \ +- int __tmp; \ +- extern void *__tls_get_addr (void *); \ +- asm ("nextpc %0 ; " \ +- "1: movhi %1, %%hiadj(_gp_got - 1b) ; " \ +- "addi %1, %1, %%lo(_gp_got - 1b) ; " \ +- "add %0, %0, %1 ; " \ +- "addi %0, %0, %%tls_gd(" #x ")" \ +- : "=r" (__result), "=r" (__tmp)); \ +- (int *)__tls_get_addr (__result); }) +diff --git a/sysdeps/powerpc/powerpc32/tls-macros.h b/sysdeps/powerpc/powerpc32/tls-macros.h +deleted file mode 100644 +index ee0eac4..0000000 +--- a/sysdeps/powerpc/powerpc32/tls-macros.h ++++ /dev/null +@@ -1,49 +0,0 @@ +-/* Include sysdeps/powerpc/tls-macros.h for __TLS_CALL_CLOBBERS */ +-#include_next "tls-macros.h" +- +-/* PowerPC32 Local Exec TLS access. */ +-#define TLS_LE(x) \ +- ({ int *__result; \ +- asm ("addi %0,2," #x "@tprel" \ +- : "=r" (__result)); \ +- __result; }) +- +-/* PowerPC32 Initial Exec TLS access. */ +-#define TLS_IE(x) \ +- ({ int *__result; \ +- asm ("bcl 20,31,1f\n1:\t" \ +- "mflr %0\n\t" \ +- "addis %0,%0,_GLOBAL_OFFSET_TABLE_-1b@ha\n\t" \ +- "addi %0,%0,_GLOBAL_OFFSET_TABLE_-1b@l\n\t" \ +- "lwz %0," #x "@got@tprel(%0)\n\t" \ +- "add %0,%0," #x "@tls" \ +- : "=b" (__result) : \ +- : "lr"); \ +- __result; }) +- +-/* PowerPC32 Local Dynamic TLS access. */ +-#define TLS_LD(x) \ +- ({ int *__result; \ +- asm ("bcl 20,31,1f\n1:\t" \ +- "mflr 3\n\t" \ +- "addis 3,3,_GLOBAL_OFFSET_TABLE_-1b@ha\n\t" \ +- "addi 3,3,_GLOBAL_OFFSET_TABLE_-1b@l\n\t" \ +- "addi 3,3," #x "@got@tlsld\n\t" \ +- "bl __tls_get_addr@plt\n\t" \ +- "addi %0,3," #x "@dtprel" \ +- : "=r" (__result) : \ +- : "3", __TLS_CALL_CLOBBERS); \ +- __result; }) +- +-/* PowerPC32 General Dynamic TLS access. */ +-#define TLS_GD(x) \ +- ({ register int *__result __asm__ ("r3"); \ +- asm ("bcl 20,31,1f\n1:\t" \ +- "mflr 3\n\t" \ +- "addis 3,3,_GLOBAL_OFFSET_TABLE_-1b@ha\n\t" \ +- "addi 3,3,_GLOBAL_OFFSET_TABLE_-1b@l\n\t" \ +- "addi 3,3," #x "@got@tlsgd\n\t" \ +- "bl __tls_get_addr@plt" \ +- : "=r" (__result) : \ +- : __TLS_CALL_CLOBBERS); \ +- __result; }) +diff --git a/sysdeps/powerpc/powerpc64/tls-macros.h b/sysdeps/powerpc/powerpc64/tls-macros.h +deleted file mode 100644 +index 79a0b25..0000000 +--- a/sysdeps/powerpc/powerpc64/tls-macros.h ++++ /dev/null +@@ -1,42 +0,0 @@ +-/* Include sysdeps/powerpc/tls-macros.h for __TLS_CALL_CLOBBERS */ +-#include_next "tls-macros.h" +- +-/* PowerPC64 Local Exec TLS access. */ +-#define TLS_LE(x) \ +- ({ int * __result; \ +- asm ("addis %0,13," #x "@tprel@ha\n\t" \ +- "addi %0,%0," #x "@tprel@l" \ +- : "=b" (__result) ); \ +- __result; \ +- }) +-/* PowerPC64 Initial Exec TLS access. */ +-#define TLS_IE(x) \ +- ({ int * __result; \ +- asm ("ld %0," #x "@got@tprel(2)\n\t" \ +- "add %0,%0," #x "@tls" \ +- : "=r" (__result) ); \ +- __result; \ +- }) +- +-/* PowerPC64 Local Dynamic TLS access. */ +-#define TLS_LD(x) \ +- ({ int * __result; \ +- asm ("addi 3,2," #x "@got@tlsld\n\t" \ +- "bl __tls_get_addr\n\t" \ +- "nop \n\t" \ +- "addis %0,3," #x "@dtprel@ha\n\t" \ +- "addi %0,%0," #x "@dtprel@l" \ +- : "=b" (__result) : \ +- : "3", __TLS_CALL_CLOBBERS); \ +- __result; \ +- }) +-/* PowerPC64 General Dynamic TLS access. */ +-#define TLS_GD(x) \ +- ({ register int *__result __asm__ ("r3"); \ +- asm ("addi 3,2," #x "@got@tlsgd\n\t" \ +- "bl __tls_get_addr\n\t" \ +- "nop " \ +- : "=r" (__result) : \ +- : __TLS_CALL_CLOBBERS); \ +- __result; \ +- }) +diff --git a/sysdeps/powerpc/tls-macros.h b/sysdeps/powerpc/tls-macros.h +deleted file mode 100644 +index 809ef5c..0000000 +--- a/sysdeps/powerpc/tls-macros.h ++++ /dev/null +@@ -1,3 +0,0 @@ +-#define __TLS_CALL_CLOBBERS \ +- "0", "4", "5", "6", "7", "8", "9", "10", "11", "12", \ +- "lr", "ctr", "cr0", "cr1", "cr5", "cr6", "cr7" +diff --git a/sysdeps/riscv/tls-macros.h b/sysdeps/riscv/tls-macros.h +deleted file mode 100644 +index 90c496c..0000000 +--- a/sysdeps/riscv/tls-macros.h ++++ /dev/null +@@ -1,47 +0,0 @@ +-/* Macros to support TLS testing in times of missing compiler support. +- Copyright (C) 2017-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 +- . */ +- +- +-#include +-#include +-#include +-#include "dl-tls.h" +- +-#define TLS_GD(x) \ +- ({ void *__result; \ +- asm ("la.tls.gd %0, " #x "\n\t" \ +- : "=r" (__result)); \ +- __tls_get_addr (__result); }) +- +-#define TLS_LD(x) TLS_GD(x) +- +-#define TLS_IE(x) \ +- ({ void *__result; \ +- asm ("la.tls.ie %0, " #x "\n\t" \ +- "add %0, %0, tp\n\t" \ +- : "=r" (__result)); \ +- __result; }) +- +-#define TLS_LE(x) \ +- ({ void *__result; \ +- asm ("lui %0, %%tprel_hi(" #x ")\n\t" \ +- "add %0, %0, tp, %%tprel_add(" #x ")\n\t" \ +- "addi %0, %0, %%tprel_lo(" #x ")\n\t" \ +- : "=r" (__result)); \ +- __result; }) +diff --git a/sysdeps/s390/s390-32/tls-macros.h b/sysdeps/s390/s390-32/tls-macros.h +deleted file mode 100644 +index 153523a..0000000 +--- a/sysdeps/s390/s390-32/tls-macros.h ++++ /dev/null +@@ -1,106 +0,0 @@ +-#define TLS_LE(x) \ +- ({ unsigned long __offset; \ +- __asm__ ("bras %0,1f\n" \ +- "0:\t.long " #x "@ntpoff\n" \ +- "1:\tl %0,0(%0)" \ +- : "=a" (__offset) : : "cc" ); \ +- (int *) (__builtin_thread_pointer() + __offset); }) +- +-#ifdef PIC +-# define TLS_IE(x) \ +- ({ unsigned long __offset, __save12; \ +- __asm__ ("bras %0,1f\n" \ +- "0:\t.long _GLOBAL_OFFSET_TABLE_-0b\n\t" \ +- ".long " #x "@gotntpoff\n" \ +- "1:\tlr %1,%%r12\n\t" \ +- "l %%r12,0(%0)\n\t" \ +- "la %%r12,0(%0,%%r12)\n\t" \ +- "l %0,4(%0)\n\t" \ +- "l %0,0(%0,%%r12):tls_load:" #x "\n\t" \ +- "lr %%r12,%1\n" \ +- : "=&a" (__offset), "=&a" (__save12) : : "cc" ); \ +- (int *) (__builtin_thread_pointer() + __offset); }) +-#else +-# define TLS_IE(x) \ +- ({ unsigned long __offset; \ +- __asm__ ("bras %0,1f\n" \ +- "0:\t.long " #x "@indntpoff\n" \ +- "1:\t l %0,0(%0)\n\t" \ +- "l %0,0(%0):tls_load:" #x \ +- : "=&a" (__offset) : : "cc" ); \ +- (int *) (__builtin_thread_pointer() + __offset); }) +-#endif +- +-#ifdef PIC +-# define TLS_LD(x) \ +- ({ unsigned long __offset, __save12; \ +- __asm__ ("bras %0,1f\n" \ +- "0:\t.long _GLOBAL_OFFSET_TABLE_-0b\n\t" \ +- ".long __tls_get_offset@plt-0b\n\t" \ +- ".long " #x "@tlsldm\n\t" \ +- ".long " #x "@dtpoff\n" \ +- "1:\tlr %1,%%r12\n\t" \ +- "l %%r12,0(%0)\n\t" \ +- "la %%r12,0(%%r12,%0)\n\t" \ +- "l %%r1,4(%0)\n\t" \ +- "l %%r2,8(%0)\n\t" \ +- "bas %%r14,0(%%r1,%0):tls_ldcall:" #x "\n\t" \ +- "l %0,12(%0)\n\t" \ +- "alr %0,%%r2\n\t" \ +- "lr %%r12,%1" \ +- : "=&a" (__offset), "=&a" (__save12) \ +- : : "cc", "0", "1", "2", "3", "4", "5", "14"); \ +- (int *) (__builtin_thread_pointer() + __offset); }) +-#else +-# define TLS_LD(x) \ +- ({ unsigned long __offset; \ +- __asm__ ("bras %0,1f\n" \ +- "0:\t.long _GLOBAL_OFFSET_TABLE_\n\t" \ +- ".long __tls_get_offset@plt\n\t" \ +- ".long " #x "@tlsldm\n\t" \ +- ".long " #x "@dtpoff\n" \ +- "1:\tl %%r12,0(%0)\n\t" \ +- "l %%r1,4(%0)\n\t" \ +- "l %%r2,8(%0)\n\t" \ +- "bas %%r14,0(%%r1):tls_ldcall:" #x "\n\t" \ +- "l %0,12(%0)\n\t" \ +- "alr %0,%%r2" \ +- : "=&a" (__offset) \ +- : : "cc", "0", "1", "2", "3", "4", "5", "12", "14"); \ +- (int *) (__builtin_thread_pointer() + __offset); }) +-#endif +- +-#ifdef PIC +-# define TLS_GD(x) \ +- ({ unsigned long __offset, __save12; \ +- __asm__ ("bras %0,1f\n" \ +- "0:\t.long _GLOBAL_OFFSET_TABLE_-0b\n\t" \ +- ".long __tls_get_offset@plt-0b\n\t" \ +- ".long " #x "@tlsgd\n" \ +- "1:\tlr %1,%%r12\n\t" \ +- "l %%r12,0(%0)\n\t" \ +- "la %%r12,0(%%r12,%0)\n\t" \ +- "l %%r1,4(%0)\n\t" \ +- "l %%r2,8(%0)\n\t" \ +- "bas %%r14,0(%%r1,%0):tls_gdcall:" #x "\n\t" \ +- "lr %0,%%r2\n\t" \ +- "lr %%r12,%1" \ +- : "=&a" (__offset), "=&a" (__save12) \ +- : : "cc", "0", "1", "2", "3", "4", "5", "14"); \ +- (int *) (__builtin_thread_pointer() + __offset); }) +-#else +-# define TLS_GD(x) \ +- ({ unsigned long __offset; \ +- __asm__ ("bras %0,1f\n" \ +- "0:\t.long _GLOBAL_OFFSET_TABLE_\n\t" \ +- ".long __tls_get_offset@plt\n\t" \ +- ".long " #x "@tlsgd\n" \ +- "1:\tl %%r12,0(%0)\n\t" \ +- "l %%r1,4(%0)\n\t" \ +- "l %%r2,8(%0)\n\t" \ +- "bas %%r14,0(%%r1):tls_gdcall:" #x "\n\t" \ +- "lr %0,%%r2" \ +- : "=&a" (__offset) \ +- : : "cc", "0", "1", "2", "3", "4", "5", "12", "14"); \ +- (int *) (__builtin_thread_pointer() + __offset); }) +-#endif +diff --git a/sysdeps/s390/s390-64/tls-macros.h b/sysdeps/s390/s390-64/tls-macros.h +deleted file mode 100644 +index 449a843..0000000 +--- a/sysdeps/s390/s390-64/tls-macros.h ++++ /dev/null +@@ -1,90 +0,0 @@ +-#define TLS_LE(x) \ +- ({ unsigned long __offset; \ +- __asm__ ("bras %0,1f\n" \ +- "0:\t.quad " #x "@ntpoff\n" \ +- "1:\tlg %0,0(%0)" \ +- : "=a" (__offset) : : "cc" ); \ +- (int *) (__builtin_thread_pointer() + __offset); }) +- +-#ifdef PIC +-# define TLS_IE(x) \ +- ({ unsigned long __offset, __save12; \ +- __asm__ ("bras %0,0f\n\t" \ +- ".quad " #x "@gotntpoff\n" \ +- "0:\tlgr %1,%%r12\n\t" \ +- "larl %%r12,_GLOBAL_OFFSET_TABLE_\n\t" \ +- "lg %0,0(%0)\n\t" \ +- "lg %0,0(%0,%%r12):tls_load:" #x "\n\t" \ +- "lgr %%r12,%1\n" \ +- : "=&a" (__offset), "=&a" (__save12) : : "cc" ); \ +- (int *) (__builtin_thread_pointer() + __offset); }) +-#else +-# define TLS_IE(x) \ +- ({ unsigned long __offset; \ +- __asm__ ("bras %0,1f\n" \ +- "0:\t.quad " #x "@indntpoff\n" \ +- "1:\t lg %0,0(%0)\n\t" \ +- "lg %0,0(%0):tls_load:" #x \ +- : "=&a" (__offset) : : "cc" ); \ +- (int *) (__builtin_thread_pointer() + __offset); }) +-#endif +- +-#ifdef PIC +-# define TLS_LD(x) \ +- ({ unsigned long __offset, __save12; \ +- __asm__ ("bras %0,1f\n" \ +- "0:\t.quad " #x "@tlsldm\n\t" \ +- ".quad " #x "@dtpoff\n" \ +- "1:\tlgr %1,%%r12\n\t" \ +- "larl %%r12,_GLOBAL_OFFSET_TABLE_\n\t" \ +- "lg %%r2,0(%0)\n\t" \ +- "brasl %%r14,__tls_get_offset@plt:tls_ldcall:" #x "\n\t" \ +- "lg %0,8(%0)\n\t" \ +- "algr %0,%%r2\n\t" \ +- "lgr %%r12,%1" \ +- : "=&a" (__offset), "=&a" (__save12) \ +- : : "cc", "0", "1", "2", "3", "4", "5", "14" ); \ +- (int *) (__builtin_thread_pointer() + __offset); }) +-#else +-# define TLS_LD(x) \ +- ({ unsigned long __offset; \ +- __asm__ ("bras %0,1f\n" \ +- "0:\t.quad " #x "@tlsldm\n\t" \ +- ".quad " #x "@dtpoff\n" \ +- "1:\tlarl %%r12,_GLOBAL_OFFSET_TABLE_\n\t" \ +- "lg %%r2,0(%0)\n\t" \ +- "brasl %%r14,__tls_get_offset@plt:tls_ldcall:" #x "\n\t" \ +- "lg %0,8(%0)\n\t" \ +- "algr %0,%%r2" \ +- : "=&a" (__offset) \ +- : : "cc", "0", "1", "2", "3", "4", "5", "12", "14" ); \ +- (int *) (__builtin_thread_pointer() + __offset); }) +-#endif +- +-#ifdef PIC +-# define TLS_GD(x) \ +- ({ unsigned long __offset, __save12; \ +- __asm__ ("bras %0,1f\n" \ +- "0:\t.quad " #x "@tlsgd\n" \ +- "1:\tlgr %1,%%r12\n\t" \ +- "larl %%r12,_GLOBAL_OFFSET_TABLE_\n\t" \ +- "lg %%r2,0(%0)\n\t" \ +- "brasl %%r14,__tls_get_offset@plt:tls_gdcall:" #x "\n\t" \ +- "lgr %0,%%r2\n\t" \ +- "lgr %%r12,%1" \ +- : "=&a" (__offset), "=&a" (__save12) \ +- : : "cc", "0", "1", "2", "3", "4", "5", "14" ); \ +- (int *) (__builtin_thread_pointer() + __offset); }) +-#else +-# define TLS_GD(x) \ +- ({ unsigned long __offset; \ +- __asm__ ("bras %0,1f\n" \ +- "0:\t.quad " #x "@tlsgd\n" \ +- "1:\tlarl %%r12,_GLOBAL_OFFSET_TABLE_\n\t" \ +- "lg %%r2,0(%0)\n\t" \ +- "brasl %%r14,__tls_get_offset@plt:tls_gdcall:" #x "\n\t" \ +- "lgr %0,%%r2" \ +- : "=&a" (__offset) \ +- : : "cc", "0", "1", "2", "3", "4", "5", "12", "14" ); \ +- (int *) (__builtin_thread_pointer() + __offset); }) +-#endif +diff --git a/sysdeps/sh/tls-macros.h b/sysdeps/sh/tls-macros.h +deleted file mode 100644 +index aa56b0a..0000000 +--- a/sysdeps/sh/tls-macros.h ++++ /dev/null +@@ -1,143 +0,0 @@ +-#define TLS_LE(x) \ +- ({ int *__l; void *__tp; \ +- asm ("stc gbr,%1\n\t" \ +- "mov.l 1f,%0\n\t" \ +- "bra 2f\n\t" \ +- " add %1,%0\n\t" \ +- ".align 2\n\t" \ +- "1: .long " #x "@tpoff\n\t" \ +- "2:" \ +- : "=r" (__l), "=r" (__tp)); \ +- __l; }) +- +-#ifdef PIC +-# define TLS_IE(x) \ +- ({ int *__l; void *__tp; \ +- register void *__gp __asm__("r12"); \ +- asm ("mov.l 1f,r0\n\t" \ +- "stc gbr,%1\n\t" \ +- "mov.l @(r0,r12),%0\n\t" \ +- "bra 2f\n\t" \ +- " add %1,%0\n\t" \ +- ".align 2\n\t" \ +- "1: .long " #x "@gottpoff\n\t" \ +- "2:" \ +- : "=r" (__l), "=r" (__tp) : "r" (__gp) : "r0"); \ +- __l; }) +-#else +-# define TLS_IE(x) \ +- ({ int *__l; void *__tp; \ +- asm ("mov.l r12,@-r15\n\t" \ +- "mova 0f,r0\n\t" \ +- "mov.l 0f,r12\n\t" \ +- "add r0,r12\n\t" \ +- "mov.l 1f,r0\n\t" \ +- "stc gbr,%1\n\t" \ +- "mov.l @(r0,r12),%0\n\t" \ +- "bra 2f\n\t" \ +- " add %1,%0\n\t" \ +- ".align 2\n\t" \ +- "1: .long " #x "@gottpoff\n\t" \ +- "0: .long _GLOBAL_OFFSET_TABLE_\n\t" \ +- "2: mov.l @r15+,r12" \ +- : "=r" (__l), "=r" (__tp) : : "r0"); \ +- __l; }) +-#endif +- +-#ifdef PIC +-# define TLS_LD(x) \ +- ({ int *__l; \ +- register void *__gp __asm__("r12"); \ +- asm ("mov.l 1f,r4\n\t" \ +- "mova 2f,r0\n\t" \ +- "mov.l 2f,r1\n\t" \ +- "add r0,r1\n\t" \ +- "jsr @r1\n\t" \ +- " add r12,r4\n\t" \ +- "bra 4f\n\t" \ +- " nop\n\t" \ +- ".align 2\n\t" \ +- "1: .long " #x "@tlsldm\n\t" \ +- "2: .long __tls_get_addr@plt\n\t" \ +- "4: mov.l 3f,%0\n\t" \ +- "bra 5f\n\t" \ +- " add r0,%0\n\t" \ +- ".align 2\n\t" \ +- "3: .long " #x "@dtpoff\n\t" \ +- "5:" \ +- : "=r" (__l) : "r" (__gp) : "r0", "r1", "r2", "r3", "r4", "r5", \ +- "r6", "r7", "pr", "t"); \ +- __l; }) +-#else +-# define TLS_LD(x) \ +- ({ int *__l; \ +- asm ("mov.l r12,@-r15\n\t" \ +- "mova 0f,r0\n\t" \ +- "mov.l 0f,r12\n\t" \ +- "add r0,r12\n\t" \ +- "mov.l 1f,r4\n\t" \ +- "mova 2f,r0\n\t" \ +- "mov.l 2f,r1\n\t" \ +- "add r0,r1\n\t" \ +- "jsr @r1\n\t" \ +- " add r12,r4\n\t" \ +- "bra 4f\n\t" \ +- " nop\n\t" \ +- ".align 2\n\t" \ +- "1: .long " #x "@tlsldm\n\t" \ +- "2: .long __tls_get_addr@plt\n\t" \ +- "0: .long _GLOBAL_OFFSET_TABLE_\n\t" \ +- "4: mov.l 3f,%0\n\t" \ +- "bra 5f\n\t" \ +- " add r0,%0\n\t" \ +- ".align 2\n\t" \ +- "3: .long " #x "@dtpoff\n\t" \ +- "5: mov.l @r15+,r12" \ +- : "=r" (__l) : : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ +- "pr", "t"); \ +- __l; }) +-#endif +- +-#ifdef PIC +-# define TLS_GD(x) \ +- ({ int *__l; \ +- register void *__gp __asm__("r12"); \ +- asm ("mov.l 1f,r4\n\t" \ +- "mova 2f,r0\n\t" \ +- "mov.l 2f,r1\n\t" \ +- "add r0,r1\n\t" \ +- "jsr @r1\n\t" \ +- " add r12,r4\n\t" \ +- "bra 3f\n\t" \ +- " mov r0,%0\n\t" \ +- ".align 2\n\t" \ +- "1: .long " #x "@tlsgd\n\t" \ +- "2: .long __tls_get_addr@plt\n\t" \ +- "3:" \ +- : "=r" (__l) : "r" (__gp) : "r0", "r1", "r2", "r3", "r4", "r5", \ +- "r6", "r7", "pr", "t"); \ +- __l; }) +-#else +-# define TLS_GD(x) \ +- ({ int *__l; \ +- asm ("mov.l r12,@-r15\n\t" \ +- "mova 0f,r0\n\t" \ +- "mov.l 0f,r12\n\t" \ +- "add r0,r12\n\t" \ +- "mov.l 1f,r4\n\t" \ +- "mova 2f,r0\n\t" \ +- "mov.l 2f,r1\n\t" \ +- "add r0,r1\n\t" \ +- "jsr @r1\n\t" \ +- " add r12,r4\n\t" \ +- "bra 3f\n\t" \ +- " mov r0,%0\n\t" \ +- ".align 2\n\t" \ +- "1: .long " #x "@tlsgd\n\t" \ +- "2: .long __tls_get_addr@plt\n\t" \ +- "0: .long _GLOBAL_OFFSET_TABLE_\n\t" \ +- "3: mov.l @r15+,r12" \ +- : "=r" (__l) : : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ +- "pr", "t"); \ +- __l; }) +-#endif +diff --git a/sysdeps/sparc/sparc32/tls-macros.h b/sysdeps/sparc/sparc32/tls-macros.h +deleted file mode 100644 +index 152216e..0000000 +--- a/sysdeps/sparc/sparc32/tls-macros.h ++++ /dev/null +@@ -1,66 +0,0 @@ +-#define TLS_LE(x) \ +- ({ int *__l; \ +- asm ("sethi %%tle_hix22(" #x "), %0" : "=r" (__l)); \ +- asm ("xor %1, %%tle_lox10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ +- asm ("add %%g7, %1, %0" : "=r" (__l) : "r" (__l)); \ +- __l; }) +- +-#ifdef __PIC__ +-# define TLS_LOAD_PIC \ +- ({ register long pc __asm__ ("%o7"); \ +- long got; \ +- asm ("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t" \ +- "call .+8\n\t" \ +- "add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n\t" \ +- "add %1, %0, %1\n\t" \ +- : "=r" (pc), "=r" (got)); \ +- got; }) +-#else +-# define TLS_LOAD_PIC \ +- ({ long got; \ +- asm (".hidden _GLOBAL_OFFSET_TABLE_\n\t" \ +- "sethi %%hi(_GLOBAL_OFFSET_TABLE_), %0\n\t" \ +- "or %0, %%lo(_GLOBAL_OFFSET_TABLE_), %0" \ +- : "=r" (got)); \ +- got; }) +-#endif +- +-#define TLS_IE(x) \ +- ({ int *__l; \ +- asm ("sethi %%tie_hi22(" #x "), %0" : "=r" (__l)); \ +- asm ("add %1, %%tie_lo10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ +- asm ("ld [%1 + %2], %0, %%tie_ld(" #x ")" \ +- : "=r" (__l) : "r" (TLS_LOAD_PIC), "r" (__l)); \ +- asm ("add %%g7, %1, %0, %%tie_add(" #x ")" : "=r" (__l) : "r" (__l)); \ +- __l; }) +- +-#define TLS_LD(x) \ +- ({ int *__l; register void *__o0 asm ("%o0"); \ +- long __o; \ +- asm ("sethi %%tldm_hi22(" #x "), %0" : "=r" (__l)); \ +- asm ("add %1, %%tldm_lo10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ +- asm ("add %1, %2, %0, %%tldm_add(" #x ")" \ +- : "=r" (__o0) : "r" (TLS_LOAD_PIC), "r" (__l)); \ +- asm ("call __tls_get_addr, %%tgd_call(" #x ")\n\t" \ +- " nop" \ +- : "=r" (__o0) : "0" (__o0) \ +- : "g1", "g2", "g3", "g4", "g5", "g6", "o1", "o2", "o3", "o4", \ +- "o5", "o7", "cc"); \ +- asm ("sethi %%tldo_hix22(" #x "), %0" : "=r" (__o)); \ +- asm ("xor %1, %%tldo_lox10(" #x "), %0" : "=r" (__o) : "r" (__o)); \ +- asm ("add %1, %2, %0, %%tldo_add(" #x ")" : "=r" (__l) \ +- : "r" (__o0), "r" (__o)); \ +- __l; }) +- +-#define TLS_GD(x) \ +- ({ int *__l; register void *__o0 asm ("%o0"); \ +- asm ("sethi %%tgd_hi22(" #x "), %0" : "=r" (__l)); \ +- asm ("add %1, %%tgd_lo10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ +- asm ("add %1, %2, %0, %%tgd_add(" #x ")" \ +- : "=r" (__o0) : "r" (TLS_LOAD_PIC), "r" (__l)); \ +- asm ("call __tls_get_addr, %%tgd_call(" #x ")\n\t" \ +- " nop" \ +- : "=r" (__o0) : "0" (__o0) \ +- : "g1", "g2", "g3", "g4", "g5", "g6", "o1", "o2", "o3", "o4", \ +- "o5", "o7", "cc"); \ +- __o0; }) +diff --git a/sysdeps/sparc/sparc64/tls-macros.h b/sysdeps/sparc/sparc64/tls-macros.h +deleted file mode 100644 +index bb0d803..0000000 +--- a/sysdeps/sparc/sparc64/tls-macros.h ++++ /dev/null +@@ -1,65 +0,0 @@ +-#define TLS_LE(x) \ +- ({ int *__l; \ +- asm ("sethi %%tle_hix22(" #x "), %0" : "=r" (__l)); \ +- asm ("xor %1, %%tle_lox10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ +- asm ("add %%g7, %1, %0" : "=r" (__l) : "r" (__l)); \ +- __l; }) +- +-#ifdef __PIC__ +-# define TLS_LOAD_PIC \ +- ({ long pc, got; \ +- asm ("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t" \ +- "rd %%pc, %0\n\t" \ +- "add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n\t" \ +- "add %1, %0, %1\n\t" \ +- : "=r" (pc), "=r" (got)); \ +- got; }) +-#else +-# define TLS_LOAD_PIC \ +- ({ long got; \ +- asm (".hidden _GLOBAL_OFFSET_TABLE_\n\t" \ +- "sethi %%hi(_GLOBAL_OFFSET_TABLE_), %0\n\t" \ +- "or %0, %%lo(_GLOBAL_OFFSET_TABLE_), %0" \ +- : "=r" (got)); \ +- got; }) +-#endif +- +-#define TLS_IE(x) \ +- ({ int *__l; \ +- asm ("sethi %%tie_hi22(" #x "), %0" : "=r" (__l)); \ +- asm ("add %1, %%tie_lo10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ +- asm ("ldx [%1 + %2], %0, %%tie_ldx(" #x ")" \ +- : "=r" (__l) : "r" (TLS_LOAD_PIC), "r" (__l)); \ +- asm ("add %%g7, %1, %0, %%tie_add(" #x ")" : "=r" (__l) : "r" (__l)); \ +- __l; }) +- +-#define TLS_LD(x) \ +- ({ int *__l; register void *__o0 asm ("%o0"); \ +- long __o; \ +- asm ("sethi %%tldm_hi22(" #x "), %0" : "=r" (__l)); \ +- asm ("add %1, %%tldm_lo10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ +- asm ("add %1, %2, %0, %%tldm_add(" #x ")" \ +- : "=r" (__o0) : "r" (TLS_LOAD_PIC), "r" (__l)); \ +- asm ("call __tls_get_addr, %%tgd_call(" #x ")\n\t" \ +- " nop" \ +- : "=r" (__o0) : "0" (__o0) \ +- : "g1", "g2", "g3", "g4", "g5", "g6", "o1", "o2", "o3", "o4", \ +- "o5", "o7", "cc"); \ +- asm ("sethi %%tldo_hix22(" #x "), %0" : "=r" (__o)); \ +- asm ("xor %1, %%tldo_lox10(" #x "), %0" : "=r" (__o) : "r" (__o)); \ +- asm ("add %1, %2, %0, %%tldo_add(" #x ")" : "=r" (__l) \ +- : "r" (__o0), "r" (__o)); \ +- __l; }) +- +-#define TLS_GD(x) \ +- ({ int *__l; register void *__o0 asm ("%o0"); \ +- asm ("sethi %%tgd_hi22(" #x "), %0" : "=r" (__l)); \ +- asm ("add %1, %%tgd_lo10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ +- asm ("add %1, %2, %0, %%tgd_add(" #x ")" \ +- : "=r" (__o0) : "r" (TLS_LOAD_PIC), "r" (__l)); \ +- asm ("call __tls_get_addr, %%tgd_call(" #x ")\n\t" \ +- " nop" \ +- : "=r" (__o0) : "0" (__o0) \ +- : "g1", "g2", "g3", "g4", "g5", "g6", "o1", "o2", "o3", "o4", \ +- "o5", "o7", "cc"); \ +- __o0; }) +diff --git a/sysdeps/x86_64/tls-macros.h b/sysdeps/x86_64/tls-macros.h +deleted file mode 100644 +index 22d2a4b..0000000 +--- a/sysdeps/x86_64/tls-macros.h ++++ /dev/null +@@ -1,39 +0,0 @@ +-#define TLS_LE(x) \ +- ({ int *__l; \ +- asm ("mov %%fs:0,%0\n\t" \ +- "lea " #x "@tpoff(%0), %0" \ +- : "=r" (__l)); \ +- __l; }) +- +-#define TLS_IE(x) \ +- ({ int *__l; \ +- asm ("mov %%fs:0,%0\n\t" \ +- "add " #x "@gottpoff(%%rip),%0" \ +- : "=r" (__l)); \ +- __l; }) +- +-#define TLS_LD(x) \ +- ({ int *__l, __c, __d; \ +- asm ("leaq " #x "@tlsld(%%rip),%%rdi\n\t" \ +- "call __tls_get_addr@plt\n\t" \ +- "leaq " #x "@dtpoff(%%rax), %%rax" \ +- : "=a" (__l), "=&c" (__c), "=&d" (__d) \ +- : : "rdi", "rsi", "r8", "r9", "r10", "r11"); \ +- __l; }) +- +-#ifdef __ILP32__ +-# define TLS_GD_PREFIX +-#else +-# define TLS_GD_PREFIX ".byte 0x66\n\t" +-#endif +- +-#define TLS_GD(x) \ +- ({ int *__l, __c, __d; \ +- asm (TLS_GD_PREFIX \ +- "leaq " #x "@tlsgd(%%rip),%%rdi\n\t" \ +- ".word 0x6666\n\t" \ +- "rex64\n\t" \ +- "call __tls_get_addr@plt" \ +- : "=a" (__l), "=&c" (__c), "=&d" (__d) \ +- : : "rdi", "rsi", "r8", "r9", "r10", "r11"); \ +- __l; }) +-- +1.8.3.1 + diff --git a/Update-string-test-memmove.c-to-cover-16KB-copy.patch b/Update-string-test-memmove.c-to-cover-16KB-copy.patch new file mode 100644 index 0000000000000000000000000000000000000000..894833e457bf199b4ed9e809080f0a3576f9ffba --- /dev/null +++ b/Update-string-test-memmove.c-to-cover-16KB-copy.patch @@ -0,0 +1,78 @@ +From c333dcf8d8f9e6e46475d9eff24bd5394b5d3d9e Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Mon, 1 Feb 2021 17:23:12 -0800 +Subject: [PATCH] Update string/test-memmove.c to cover 16KB copy + +--- + string/test-memmove.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 48 insertions(+) + +diff --git a/string/test-memmove.c b/string/test-memmove.c +index b271248..670094c 100644 +--- a/string/test-memmove.c ++++ b/string/test-memmove.c +@@ -312,6 +312,50 @@ do_test2 (size_t offset) + munmap ((void *) large_buf, size); + } + ++static void ++do_test3 (size_t bytes_move, size_t offset) ++{ ++ size_t size = bytes_move * 3; ++ uint32_t *buf; ++ ++ buf = mmap (NULL, size, PROT_READ | PROT_WRITE, ++ MAP_PRIVATE | MAP_ANON, -1, 0); ++ ++ if (buf == MAP_FAILED) ++ error (EXIT_UNSUPPORTED, errno, "mmap failed"); ++ ++ size_t arr_size = bytes_move / sizeof (uint32_t); ++ size_t i; ++ ++ FOR_EACH_IMPL (impl, 0) ++ { ++ for (i = 0; i < arr_size; i++) ++ buf[i] = (uint32_t) i; ++ ++ uint32_t *dst = &buf[arr_size + offset]; ++ ++#ifdef TEST_BCOPY ++ CALL (impl, (char *) buf, (char *) dst, bytes_move); ++#else ++ CALL (impl, (char *) dst, (char *) buf, bytes_move); ++#endif ++ ++ for (i = 0; i < arr_size; i++) ++ { ++ if (dst[i] != (uint32_t) i) ++ { ++ error (0, 0, ++ "Wrong result in function %s dst \"%p\" src \"%p\" offset \"%zd\"", ++ impl->name, dst, buf, i); ++ ret = 1; ++ break; ++ } ++ } ++ } ++ ++ munmap ((void *) buf, size); ++} ++ + int + test_main (void) + { +@@ -356,6 +400,10 @@ test_main (void) + do_test2 (0x200000); + do_test2 (0x4000000 - 1); + do_test2 (0x4000000); ++ ++ /* Copy 16KB data. */ ++ do_test3 (16384, 3); ++ + return ret; + } + +-- +1.8.3.1 + diff --git a/Use-__executable_start-as-the-lowest-address-for-pro.patch b/Use-__executable_start-as-the-lowest-address-for-pro.patch new file mode 100644 index 0000000000000000000000000000000000000000..06ddfb1958de4bd0063e3d322d0cc0af4e76d494 --- /dev/null +++ b/Use-__executable_start-as-the-lowest-address-for-pro.patch @@ -0,0 +1,106 @@ +From 84a7eb1f87c1d01b58ad887a0ab5d87abbc1c772 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Fri, 30 Jul 2021 19:07:30 -0700 +Subject: [PATCH] Use __executable_start as the lowest address for profiling + [BZ #28153] + +Glibc assumes that ENTRY_POINT is the lowest address for which we need +to keep profiling records and BFD linker uses a linker script to place +the input sections. + +Starting from GCC 4.6, the main function is placed in .text.startup +section and starting from binutils 2.22, BFD linker with + +commit add44f8d5c5c05e08b11e033127a744d61c26aee +Author: Alan Modra +Date: Thu Nov 25 03:03:02 2010 +0000 + + * scripttempl/elf.sc: Group .text.exit, text.startup and .text.hot + sections. + +places .text.startup section before .text section, which leave the main +function out of profiling records. + +Starting from binutils 2.15, linker provides __executable_start to mark +the lowest address of the executable. Use __executable_start as the +lowest address to keep the main function in profiling records. This fixes +[BZ #28153]. + +Tested on Linux/x86-64, Linux/x32 and Linux/i686 as well as with +build-many-glibcs.py. +--- + csu/gmon-start.c | 10 +++++++++- + gmon/tst-gmon-gprof.sh | 2 ++ + gmon/tst-gmon-static-gprof.sh | 2 ++ + 3 files changed, 13 insertions(+), 1 deletion(-) + +diff --git a/csu/gmon-start.c b/csu/gmon-start.c +index b343288..344606a 100644 +--- a/csu/gmon-start.c ++++ b/csu/gmon-start.c +@@ -52,6 +52,11 @@ extern char ENTRY_POINT[]; + #endif + extern char etext[]; + ++/* Use __executable_start as the lowest address to keep profiling records ++ if it provided by the linker. */ ++extern const char executable_start[] asm ("__executable_start") ++ __attribute__ ((weak, visibility ("hidden"))); ++ + #ifndef TEXT_START + # ifdef ENTRY_POINT_DECL + # define TEXT_START ENTRY_POINT +@@ -92,7 +97,10 @@ __gmon_start__ (void) + called = 1; + + /* Start keeping profiling records. */ +- __monstartup ((u_long) TEXT_START, (u_long) &etext); ++ if (&executable_start != NULL) ++ __monstartup ((u_long) &executable_start, (u_long) &etext); ++ else ++ __monstartup ((u_long) TEXT_START, (u_long) &etext); + + /* Call _mcleanup before exiting; it will write out gmon.out from the + collected data. */ +diff --git a/gmon/tst-gmon-gprof.sh b/gmon/tst-gmon-gprof.sh +index 9d37158..dc0be02 100644 +--- a/gmon/tst-gmon-gprof.sh ++++ b/gmon/tst-gmon-gprof.sh +@@ -39,12 +39,14 @@ trap cleanup 0 + cat > "$expected" < "$expected_dot" < "$expected" < "$expected_dot" < +Date: Tue, 24 Aug 2021 16:15:50 -0300 +Subject: [PATCH] Use support_open_dev_null_range io/tst-closefrom, + misc/tst-close_range, and posix/tst-spawn5 (BZ #28260) + +It ensures a continuous range of file descriptor and avoid hitting +the RLIMIT_NOFILE. + +Checked on x86_64-linux-gnu. + +(cherry picked from commit 6b20880b22d1d0fce7e9f506baa6fe2d5c7fcfdc) +--- + io/tst-closefrom.c | 21 ++++++--------------- + posix/tst-spawn5.c | 13 +------------ + sysdeps/unix/sysv/linux/tst-close_range.c | 31 ++++++++++--------------------- + 3 files changed, 17 insertions(+), 48 deletions(-) + +diff --git a/io/tst-closefrom.c b/io/tst-closefrom.c +index d4c1870..395ec0d 100644 +--- a/io/tst-closefrom.c ++++ b/io/tst-closefrom.c +@@ -24,31 +24,22 @@ + #include + #include + #include ++#include + + #include + + #define NFDS 100 + + static int +-open_multiple_temp_files (void) +-{ +- /* Check if the temporary file descriptor has no no gaps. */ +- int lowfd = xopen ("/dev/null", O_RDONLY, 0600); +- for (int i = 1; i <= NFDS; i++) +- TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600), lowfd + i); +- return lowfd; +-} +- +-static int + closefrom_test (void) + { + struct support_descriptors *descrs = support_descriptors_list (); + +- int lowfd = open_multiple_temp_files (); ++ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600); + +- const int maximum_fd = lowfd + NFDS; ++ const int maximum_fd = lowfd + NFDS - 1; + const int half_fd = lowfd + NFDS / 2; +- const int gap = maximum_fd / 4; ++ const int gap = lowfd + NFDS / 4; + + /* Close half of the descriptors and check result. */ + closefrom (half_fd); +@@ -58,7 +49,7 @@ closefrom_test (void) + TEST_COMPARE (fcntl (i, F_GETFL), -1); + TEST_COMPARE (errno, EBADF); + } +- for (int i = 0; i < half_fd; i++) ++ for (int i = lowfd; i < half_fd; i++) + TEST_VERIFY (fcntl (i, F_GETFL) > -1); + + /* Create some gaps, close up to a threshold, and check result. */ +@@ -74,7 +65,7 @@ closefrom_test (void) + TEST_COMPARE (fcntl (i, F_GETFL), -1); + TEST_COMPARE (errno, EBADF); + } +- for (int i = 0; i < gap; i++) ++ for (int i = lowfd; i < gap; i++) + TEST_VERIFY (fcntl (i, F_GETFL) > -1); + + /* Close the remmaining but the last one. */ +diff --git a/posix/tst-spawn5.c b/posix/tst-spawn5.c +index ac66738..a95199a 100644 +--- a/posix/tst-spawn5.c ++++ b/posix/tst-spawn5.c +@@ -48,17 +48,6 @@ static int initial_argv_count; + #define NFDS 100 + + static int +-open_multiple_temp_files (void) +-{ +- /* Check if the temporary file descriptor has no no gaps. */ +- int lowfd = xopen ("/dev/null", O_RDONLY, 0600); +- for (int i = 1; i <= NFDS; i++) +- TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600), +- lowfd + i); +- return lowfd; +-} +- +-static int + parse_fd (const char *str) + { + char *endptr; +@@ -185,7 +174,7 @@ spawn_closefrom_test (posix_spawn_file_actions_t *fa, int lowfd, int highfd, + static void + do_test_closefrom (void) + { +- int lowfd = open_multiple_temp_files (); ++ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600); + const int half_fd = lowfd + NFDS / 2; + + /* Close half of the descriptors and check result. */ +diff --git a/sysdeps/unix/sysv/linux/tst-close_range.c b/sysdeps/unix/sysv/linux/tst-close_range.c +index dccb618..f5069d1 100644 +--- a/sysdeps/unix/sysv/linux/tst-close_range.c ++++ b/sysdeps/unix/sysv/linux/tst-close_range.c +@@ -36,23 +36,12 @@ + + #define NFDS 100 + +-static int +-open_multiple_temp_files (void) +-{ +- /* Check if the temporary file descriptor has no no gaps. */ +- int lowfd = xopen ("/dev/null", O_RDONLY, 0600); +- for (int i = 1; i <= NFDS; i++) +- TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600), +- lowfd + i); +- return lowfd; +-} +- + static void + close_range_test_max_upper_limit (void) + { + struct support_descriptors *descrs = support_descriptors_list (); + +- int lowfd = open_multiple_temp_files (); ++ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600); + + { + int r = close_range (lowfd, ~0U, 0); +@@ -68,7 +57,7 @@ close_range_test_max_upper_limit (void) + static void + close_range_test_common (int lowfd, unsigned int flags) + { +- const int maximum_fd = lowfd + NFDS; ++ const int maximum_fd = lowfd + NFDS - 1; + const int half_fd = lowfd + NFDS / 2; + const int gap_1 = maximum_fd - 8; + +@@ -121,7 +110,7 @@ close_range_test (void) + struct support_descriptors *descrs = support_descriptors_list (); + + /* Check if the temporary file descriptor has no no gaps. */ +- int lowfd = open_multiple_temp_files (); ++ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600); + + close_range_test_common (lowfd, 0); + +@@ -146,7 +135,7 @@ close_range_test_subprocess (void) + struct support_descriptors *descrs = support_descriptors_list (); + + /* Check if the temporary file descriptor has no no gaps. */ +- int lowfd = open_multiple_temp_files (); ++ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600); + + struct support_stack stack = support_stack_alloc (4096); + +@@ -184,7 +173,7 @@ close_range_unshare_test (void) + struct support_descriptors *descrs1 = support_descriptors_list (); + + /* Check if the temporary file descriptor has no no gaps. */ +- int lowfd = open_multiple_temp_files (); ++ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600); + + struct support_descriptors *descrs2 = support_descriptors_list (); + +@@ -200,7 +189,7 @@ close_range_unshare_test (void) + + support_stack_free (&stack); + +- for (int i = 0; i < NFDS; i++) ++ for (int i = lowfd; i < lowfd + NFDS; i++) + TEST_VERIFY (fcntl (i, F_GETFL) > -1); + + support_descriptors_check (descrs2); +@@ -226,9 +215,9 @@ static void + close_range_cloexec_test (void) + { + /* Check if the temporary file descriptor has no no gaps. */ +- const int lowfd = open_multiple_temp_files (); ++ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600); + +- const int maximum_fd = lowfd + NFDS; ++ const int maximum_fd = lowfd + NFDS - 1; + const int half_fd = lowfd + NFDS / 2; + const int gap_1 = maximum_fd - 8; + +@@ -251,13 +240,13 @@ close_range_cloexec_test (void) + /* Create some gaps, close up to a threshold, and check result. */ + static int gap_close[] = { 57, 78, 81, 82, 84, 90 }; + for (int i = 0; i < array_length (gap_close); i++) +- xclose (gap_close[i]); ++ xclose (lowfd + gap_close[i]); + + TEST_COMPARE (close_range (half_fd + 1, gap_1, CLOSE_RANGE_CLOEXEC), 0); + for (int i = half_fd + 1; i < gap_1; i++) + { + int flags = fcntl (i, F_GETFD); +- if (is_in_array (gap_close, array_length (gap_close), i)) ++ if (is_in_array (gap_close, array_length (gap_close), i - lowfd)) + TEST_COMPARE (flags, -1); + else + { +-- +1.8.3.1 + diff --git a/aarch64-Make-elf_machine_-load_address-dynamic-robus.patch b/aarch64-Make-elf_machine_-load_address-dynamic-robus.patch new file mode 100644 index 0000000000000000000000000000000000000000..b17849954135668bd06c9ba120438c24be25200a --- /dev/null +++ b/aarch64-Make-elf_machine_-load_address-dynamic-robus.patch @@ -0,0 +1,72 @@ +From 43d06ed218fc8be58987bdfd00e21e5720f0b862 Mon Sep 17 00:00:00 2001 +From: Fangrui Song +Date: Wed, 11 Aug 2021 09:00:37 -0700 +Subject: [PATCH] aarch64: Make elf_machine_{load_address,dynamic} robust [BZ + #28203] + +The AArch64 ABI is largely platform agnostic and does not specify +_GLOBAL_OFFSET_TABLE_[0] ([1]). glibc ld.so turns out to be probably the +only user of _GLOBAL_OFFSET_TABLE_[0] and GNU ld defines the value +to the link-time address _DYNAMIC. [2] + +In 2012, __ehdr_start was implemented in GNU ld and gold in binutils +2.23. Using adrp+add / (-mcmodel=tiny) adr to access +__ehdr_start/_DYNAMIC gives us a robust way to get the load address and +the link-time address of _DYNAMIC. + +[1]: From a psABI maintainer, https://bugs.llvm.org/show_bug.cgi?id=49672#c2 +[2]: LLD's aarch64 port does not set _GLOBAL_OFFSET_TABLE_[0] to the +link-time address _DYNAMIC. +LLD is widely used on aarch64 Android and ChromeOS devices. Software +just works without the need for _GLOBAL_OFFSET_TABLE_[0]. + +Reviewed-by: Szabolcs Nagy +--- + sysdeps/aarch64/dl-machine.h | 24 +++++++++--------------- + 1 file changed, 9 insertions(+), 15 deletions(-) + +diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h +index d29d827..3e10cb4 100644 +--- a/sysdeps/aarch64/dl-machine.h ++++ b/sysdeps/aarch64/dl-machine.h +@@ -37,28 +37,22 @@ elf_machine_matches_host (const ElfW(Ehdr) *ehdr) + return ehdr->e_machine == EM_AARCH64; + } + +-/* Return the link-time address of _DYNAMIC. Conveniently, this is the +- first element of the GOT. */ +-static inline ElfW(Addr) __attribute__ ((unused)) +-elf_machine_dynamic (void) +-{ +- extern const ElfW(Addr) _GLOBAL_OFFSET_TABLE_[] attribute_hidden; +- return _GLOBAL_OFFSET_TABLE_[0]; +-} +- + /* Return the run-time load address of the shared object. */ + + static inline ElfW(Addr) __attribute__ ((unused)) + elf_machine_load_address (void) + { +- /* To figure out the load address we use the definition that for any symbol: +- dynamic_addr(symbol) = static_addr(symbol) + load_addr ++ extern const ElfW(Ehdr) __ehdr_start attribute_hidden; ++ return (ElfW(Addr)) &__ehdr_start; ++} + +- _DYNAMIC sysmbol is used here as its link-time address stored in +- the special unrelocated first GOT entry. */ ++/* Return the link-time address of _DYNAMIC. */ + +- extern ElfW(Dyn) _DYNAMIC[] attribute_hidden; +- return (ElfW(Addr)) &_DYNAMIC - elf_machine_dynamic (); ++static inline ElfW(Addr) __attribute__ ((unused)) ++elf_machine_dynamic (void) ++{ ++ extern ElfW(Dyn) _DYNAMIC[] attribute_hidden; ++ return (ElfW(Addr)) _DYNAMIC - elf_machine_load_address (); + } + + /* Set up the loaded object described by L so its unrelocated PLT +-- +1.8.3.1 + diff --git a/arm-Simplify-elf_machine_-load_address-dynamic.patch b/arm-Simplify-elf_machine_-load_address-dynamic.patch new file mode 100644 index 0000000000000000000000000000000000000000..42987ce944f01b708da4f3796f127015b6349a18 --- /dev/null +++ b/arm-Simplify-elf_machine_-load_address-dynamic.patch @@ -0,0 +1,82 @@ +From bca0f5cbc9257c13322b99e55235c4f21ba0bd82 Mon Sep 17 00:00:00 2001 +From: Fangrui Song +Date: Wed, 18 Aug 2021 11:13:03 -0700 +Subject: [PATCH] arm: Simplify elf_machine_{load_address,dynamic} + +and drop reliance on _GLOBAL_OFFSET_TABLE_[0] being the link-time +address of _DYNAMIC. &__ehdr_start is a better way to get the load address. + +This is similar to commits b37b75d269883a2c553bb7019a813094eb4e2dd1 +(x86-64) and 43d06ed218fc8be58987bdfd00e21e5720f0b862 (aarch64). + +Reviewed-by: Joseph Myers +--- + sysdeps/arm/dl-machine.h | 47 ++++++++++------------------------------------- + 1 file changed, 10 insertions(+), 37 deletions(-) + +diff --git a/sysdeps/arm/dl-machine.h b/sysdeps/arm/dl-machine.h +index ff5e09e..eb13cb8 100644 +--- a/sysdeps/arm/dl-machine.h ++++ b/sysdeps/arm/dl-machine.h +@@ -37,48 +37,21 @@ elf_machine_matches_host (const Elf32_Ehdr *ehdr) + return ehdr->e_machine == EM_ARM; + } + +- +-/* Return the link-time address of _DYNAMIC. Conveniently, this is the +- first element of the GOT. */ +-static inline Elf32_Addr __attribute__ ((unused)) +-elf_machine_dynamic (void) +-{ +- /* Declaring this hidden ensures that a PC-relative reference is used. */ +- extern const Elf32_Addr _GLOBAL_OFFSET_TABLE_[] attribute_hidden; +- return _GLOBAL_OFFSET_TABLE_[0]; +-} +- +- + /* Return the run-time load address of the shared object. */ +-static inline Elf32_Addr __attribute__ ((unused)) ++static inline ElfW(Addr) __attribute__ ((unused)) + elf_machine_load_address (void) + { +- Elf32_Addr pcrel_addr; +-#ifdef SHARED +- extern Elf32_Addr __dl_start (void *) asm ("_dl_start"); +- Elf32_Addr got_addr = (Elf32_Addr) &__dl_start; +- asm ("adr %0, _dl_start" : "=r" (pcrel_addr)); +-#else +- extern Elf32_Addr __dl_relocate_static_pie (void *) +- asm ("_dl_relocate_static_pie") attribute_hidden; +- Elf32_Addr got_addr = (Elf32_Addr) &__dl_relocate_static_pie; +- asm ("adr %0, _dl_relocate_static_pie" : "=r" (pcrel_addr)); +-#endif +-#ifdef __thumb__ +- /* Clear the low bit of the function address. +- +- NOTE: got_addr is from GOT table whose lsb is always set by linker if it's +- Thumb function address. PCREL_ADDR comes from PC-relative calculation +- which will finish during assembling. GAS assembler before the fix for +- PR gas/21458 was not setting the lsb but does after that. Always do the +- strip for both, so the code works with various combinations of glibc and +- Binutils. */ +- got_addr &= ~(Elf32_Addr) 1; +- pcrel_addr &= ~(Elf32_Addr) 1; +-#endif +- return pcrel_addr - got_addr; ++ extern const ElfW(Ehdr) __ehdr_start attribute_hidden; ++ return (ElfW(Addr)) &__ehdr_start; + } + ++/* Return the link-time address of _DYNAMIC. */ ++static inline ElfW(Addr) __attribute__ ((unused)) ++elf_machine_dynamic (void) ++{ ++ extern ElfW(Dyn) _DYNAMIC[] attribute_hidden; ++ return (ElfW(Addr)) _DYNAMIC - elf_machine_load_address (); ++} + + /* Set up the loaded object described by L so its unrelocated PLT + entries will jump to the on-demand fixup code in dl-runtime.c. */ +-- +1.8.3.1 + diff --git a/backport-CVE-2021-38604-0001-librt-add-test-bug-28213.patch b/backport-CVE-2021-38604-0001-librt-add-test-bug-28213.patch new file mode 100644 index 0000000000000000000000000000000000000000..c511b6696d42a64bab270062b635746704489b4d --- /dev/null +++ b/backport-CVE-2021-38604-0001-librt-add-test-bug-28213.patch @@ -0,0 +1,146 @@ +From 4cc79c217744743077bf7a0ec5e0a4318f1e6641 Mon Sep 17 00:00:00 2001 +From: Nikita Popov +Date: Thu, 12 Aug 2021 16:09:50 +0530 +Subject: [PATCH] librt: add test (bug 28213) + +This test implements following logic: +1) Create POSIX message queue. + Register a notification with mq_notify (using NULL attributes). + Then immediately unregister the notification with mq_notify. + Helper thread in a vulnerable version of glibc + should cause NULL pointer dereference after these steps. +2) Once again, register the same notification. + Try to send a dummy message. + Test is considered successfulif the dummy message + is successfully received by the callback function. + +Signed-off-by: Nikita Popov +Reviewed-by: Siddhesh Poyarekar +--- + rt/Makefile | 1 + + rt/tst-bz28213.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 102 insertions(+) + create mode 100644 rt/tst-bz28213.c + +diff --git a/rt/Makefile b/rt/Makefile +index 113cea03a5..910e775995 100644 +--- a/rt/Makefile ++++ b/rt/Makefile +@@ -74,6 +74,7 @@ tests := tst-shm tst-timer tst-timer2 \ + tst-aio7 tst-aio8 tst-aio9 tst-aio10 \ + tst-mqueue1 tst-mqueue2 tst-mqueue3 tst-mqueue4 \ + tst-mqueue5 tst-mqueue6 tst-mqueue7 tst-mqueue8 tst-mqueue9 \ ++ tst-bz28213 \ + tst-timer3 tst-timer4 tst-timer5 \ + tst-cpuclock2 tst-cputimer1 tst-cputimer2 tst-cputimer3 \ + tst-shm-cancel \ +diff --git a/rt/tst-bz28213.c b/rt/tst-bz28213.c +new file mode 100644 +index 0000000000..0c096b5a0a +--- /dev/null ++++ b/rt/tst-bz28213.c +@@ -0,0 +1,101 @@ ++/* Bug 28213: test for NULL pointer dereference in mq_notify. ++ Copyright (C) The GNU Toolchain Authors. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static mqd_t m = -1; ++static const char msg[] = "hello"; ++ ++static void ++check_bz28213_cb (union sigval sv) ++{ ++ char buf[sizeof (msg)]; ++ ++ (void) sv; ++ ++ TEST_VERIFY_EXIT ((size_t) mq_receive (m, buf, sizeof (buf), NULL) ++ == sizeof (buf)); ++ TEST_VERIFY_EXIT (memcmp (buf, msg, sizeof (buf)) == 0); ++ ++ exit (0); ++} ++ ++static void ++check_bz28213 (void) ++{ ++ struct sigevent sev; ++ ++ memset (&sev, '\0', sizeof (sev)); ++ sev.sigev_notify = SIGEV_THREAD; ++ sev.sigev_notify_function = check_bz28213_cb; ++ ++ /* Step 1: Register & unregister notifier. ++ Helper thread should receive NOTIFY_REMOVED notification. ++ In a vulnerable version of glibc, NULL pointer dereference follows. */ ++ TEST_VERIFY_EXIT (mq_notify (m, &sev) == 0); ++ TEST_VERIFY_EXIT (mq_notify (m, NULL) == 0); ++ ++ /* Step 2: Once again, register notification. ++ Try to send one message. ++ Test is considered successful, if the callback does exit (0). */ ++ TEST_VERIFY_EXIT (mq_notify (m, &sev) == 0); ++ TEST_VERIFY_EXIT (mq_send (m, msg, sizeof (msg), 1) == 0); ++ ++ /* Wait... */ ++ pause (); ++} ++ ++static int ++do_test (void) ++{ ++ static const char m_name[] = "/bz28213_queue"; ++ struct mq_attr m_attr; ++ ++ memset (&m_attr, '\0', sizeof (m_attr)); ++ m_attr.mq_maxmsg = 1; ++ m_attr.mq_msgsize = sizeof (msg); ++ ++ m = mq_open (m_name, ++ O_RDWR | O_CREAT | O_EXCL, ++ 0600, ++ &m_attr); ++ ++ if (m < 0) ++ { ++ if (errno == ENOSYS) ++ FAIL_UNSUPPORTED ("POSIX message queues are not implemented\n"); ++ FAIL_EXIT1 ("Failed to create POSIX message queue: %m\n"); ++ } ++ ++ TEST_VERIFY_EXIT (mq_unlink (m_name) == 0); ++ ++ check_bz28213 (); ++ ++ return 0; ++} ++ ++#include +-- +2.27.0 + diff --git a/backport-CVE-2021-38604-0002-librt-fix-NULL-pointer-dereference-bug-28213.patch b/backport-CVE-2021-38604-0002-librt-fix-NULL-pointer-dereference-bug-28213.patch new file mode 100644 index 0000000000000000000000000000000000000000..3dca8cc6cb6cc141a54ba9a4d1c4cecdf8f6e073 --- /dev/null +++ b/backport-CVE-2021-38604-0002-librt-fix-NULL-pointer-dereference-bug-28213.patch @@ -0,0 +1,39 @@ +From b805aebd42364fe696e417808a700fdb9800c9e8 Mon Sep 17 00:00:00 2001 +From: Nikita Popov +Date: Mon, 9 Aug 2021 20:17:34 +0530 +Subject: [PATCH] librt: fix NULL pointer dereference (bug 28213) + +Helper thread frees copied attribute on NOTIFY_REMOVED message +received from the OS kernel. Unfortunately, it fails to check whether +copied attribute actually exists (data.attr != NULL). This worked +earlier because free() checks passed pointer before actually +attempting to release corresponding memory. But +__pthread_attr_destroy assumes pointer is not NULL. + +So passing NULL pointer to __pthread_attr_destroy will result in +segmentation fault. This scenario is possible if +notification->sigev_notify_attributes == NULL (which means default +thread attributes should be used). + +Signed-off-by: Nikita Popov +Reviewed-by: Siddhesh Poyarekar +--- + sysdeps/unix/sysv/linux/mq_notify.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sysdeps/unix/sysv/linux/mq_notify.c b/sysdeps/unix/sysv/linux/mq_notify.c +index 9799dcdaa4..eccae2e4c6 100644 +--- a/sysdeps/unix/sysv/linux/mq_notify.c ++++ b/sysdeps/unix/sysv/linux/mq_notify.c +@@ -131,7 +131,7 @@ helper_thread (void *arg) + to wait until it is done with it. */ + (void) __pthread_barrier_wait (¬ify_barrier); + } +- else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED) ++ else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED && data.attr != NULL) + { + /* The only state we keep is the copy of the thread attributes. */ + __pthread_attr_destroy (data.attr); +-- +2.27.0 + diff --git a/copy_and_spawn_sgid-Avoid-double-calls-to-close.patch b/copy_and_spawn_sgid-Avoid-double-calls-to-close.patch new file mode 100644 index 0000000000000000000000000000000000000000..0f4799037f3950a526eb0e7357c75c5f4c6bbb7b --- /dev/null +++ b/copy_and_spawn_sgid-Avoid-double-calls-to-close.patch @@ -0,0 +1,28 @@ +From 45caed9d67a00af917d8b5b88d4b5eb1225b7aef Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +Date: Tue, 3 Aug 2021 21:10:53 +0530 +Subject: [PATCH] copy_and_spawn_sgid: Avoid double calls to close() + +If close() on infd and outfd succeeded, reset the fd numbers so that +we don't attempt to close them again. + +Reviewed-by: Arjun Shankar +--- + support/support_capture_subprocess.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c +index 27bfd19..0bacf6d 100644 +--- a/support/support_capture_subprocess.c ++++ b/support/support_capture_subprocess.c +@@ -170,6 +170,7 @@ copy_and_spawn_sgid (char *child_id, gid_t gid) + support_subprogram because we only want the program exit status, not the + contents. */ + ret = 0; ++ infd = outfd = -1; + + char * const args[] = {execname, child_id, NULL}; + +-- +1.8.3.1 + diff --git a/delete-check-installed-headers-c-and-check-installed.patch b/delete-check-installed-headers-c-and-check-installed.patch new file mode 100644 index 0000000000000000000000000000000000000000..b4fa93429db84be32cd4c600a6bd417b50c6fdc1 --- /dev/null +++ b/delete-check-installed-headers-c-and-check-installed.patch @@ -0,0 +1,60 @@ +From dd2efa50d197e2205acd8edbf29aba717d71bdbb Mon Sep 17 00:00:00 2001 +From: Yang Yanchao +Date: Tue, 4 Jan 2022 19:55:28 +0800 +Subject: [PATCH] testsuit: delete check-installed-headers-c and check-installed-headers-cxx + +check-installed-headers-c and check-installed-headers-cxx checked at CI +and can be deleted during building + +--- + Makefile | 4 ++-- + Rules | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/Makefile b/Makefile +index f98d5a9e..83200a75 100644 +--- a/Makefile ++++ b/Makefile +@@ -532,7 +532,7 @@ $(objpfx)check-local-headers.out: scripts/check-local-headers.sh + + ifneq "$(headers)" "" + # Special test of all the installed headers in this directory. +-tests-special += $(objpfx)check-installed-headers-c.out ++# tests-special += $(objpfx)check-installed-headers-c.out + libof-check-installed-headers-c := testsuite + $(objpfx)check-installed-headers-c.out: \ + scripts/check-installed-headers.sh $(headers) +@@ -542,7 +541,7 @@ $(objpfx)check-installed-headers-c.out: \ + $(evaluate-test) + + ifneq "$(CXX)" "" +-tests-special += $(objpfx)check-installed-headers-cxx.out ++# tests-special += $(objpfx)check-installed-headers-cxx.out + libof-check-installed-headers-cxx := testsuite + $(objpfx)check-installed-headers-cxx.out: \ + scripts/check-installed-headers.sh $(headers) +diff --git a/Rules b/Rules +index b1137afe..ca29abd7 100644 +--- a/Rules ++++ b/Rules +@@ -84,7 +84,7 @@ common-generated += dummy.o dummy.c + ifneq "$(headers)" "" + # Test that all of the headers installed by this directory can be compiled + # in isolation. +-tests-special += $(objpfx)check-installed-headers-c.out ++# tests-special += $(objpfx)check-installed-headers-c.out + libof-check-installed-headers-c := testsuite + $(objpfx)check-installed-headers-c.out: \ + $(..)scripts/check-installed-headers.sh $(headers) +@@ -96,7 +95,7 @@ $(objpfx)check-installed-headers-c.out: \ + ifneq "$(CXX)" "" + # If a C++ compiler is available, also test that they can be compiled + # in isolation as C++. +-tests-special += $(objpfx)check-installed-headers-cxx.out ++# tests-special += $(objpfx)check-installed-headers-cxx.out + libof-check-installed-headers-cxx := testsuite + $(objpfx)check-installed-headers-cxx.out: \ + $(..)scripts/check-installed-headers.sh $(headers) +-- +2.27.0 + diff --git a/elf-Add-a-comment-after-trailing-backslashes.patch b/elf-Add-a-comment-after-trailing-backslashes.patch new file mode 100644 index 0000000000000000000000000000000000000000..101371e36a2d9fa4e4da49f86f6f2d1437b378ba --- /dev/null +++ b/elf-Add-a-comment-after-trailing-backslashes.patch @@ -0,0 +1,49 @@ +From 511b244cc55074dc7f8476c39598d5d00811963e Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Tue, 4 Jan 2022 06:58:34 -0800 +Subject: [PATCH] elf: Add a comment after trailing backslashes + +(cherry picked from commit f4f70c2895e3d325188a42c10eb7bb4335be6773) +--- + elf/Makefile | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/elf/Makefile b/elf/Makefile +index ec1cd49bb3..5859d47fc7 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -318,6 +318,7 @@ tests-cxx = \ + tst-nodelete \ + tst-unique3 \ + tst-unique4 \ ++# tests-cxx + + tests += $(if $(CXX),$(tests-cxx)) + tests-internal += loadtest unload unload2 circleload1 \ +@@ -582,6 +583,7 @@ modules-names = \ + vismod1 \ + vismod2 \ + vismod3 \ ++# modules-names + + modules-names-cxx = \ + tst-dlopen-nodelete-reloc-mod1 \ +@@ -607,6 +609,7 @@ modules-names-cxx = \ + tst-unique3lib \ + tst-unique3lib2 \ + tst-unique4lib \ ++# modules-names-cxx + + modules-names += \ + $(if $(CXX),$(modules-names-cxx)) \ +@@ -616,6 +619,7 @@ modules-names += \ + $(tst-tls-many-dynamic-modules-dep-bad) \ + $(tlsmod17a-modules) \ + $(tlsmod18a-modules) \ ++# modules-names + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. +-- +2.27.0 + diff --git a/elf-Avoid-deadlock-between-pthread_create-and-ctors-.patch b/elf-Avoid-deadlock-between-pthread_create-and-ctors-.patch new file mode 100644 index 0000000000000000000000000000000000000000..da70902246f8c39129c73d0cd78e981e82f91bbf --- /dev/null +++ b/elf-Avoid-deadlock-between-pthread_create-and-ctors-.patch @@ -0,0 +1,482 @@ +From 83b5323261bb72313bffcf37476c1b8f0847c736 Mon Sep 17 00:00:00 2001 +From: Szabolcs Nagy +Date: Wed, 15 Sep 2021 15:16:19 +0100 +Subject: [PATCH] elf: Avoid deadlock between pthread_create and ctors [BZ + #28357] + +The fix for bug 19329 caused a regression such that pthread_create can +deadlock when concurrent ctors from dlopen are waiting for it to finish. +Use a new GL(dl_load_tls_lock) in pthread_create that is not taken +around ctors in dlopen. + +The new lock is also used in __tls_get_addr instead of GL(dl_load_lock). + +The new lock is held in _dl_open_worker and _dl_close_worker around +most of the logic before/after the init/fini routines. When init/fini +routines are running then TLS is in a consistent, usable state. +In _dl_open_worker the new lock requires catching and reraising dlopen +failures that happen in the critical section. + +The new lock is reinitialized in a fork child, to keep the existing +behaviour and it is kept recursive in case malloc interposition or TLS +access from signal handlers can retake it. It is not obvious if this +is necessary or helps, but avoids changing the preexisting behaviour. + +The new lock may be more appropriate for dl_iterate_phdr too than +GL(dl_load_write_lock), since TLS state of an incompletely loaded +module may be accessed. If the new lock can replace the old one, +that can be a separate change. + +Fixes bug 28357. + +Reviewed-by: Adhemerval Zanella +--- + elf/dl-close.c | 6 ++ + elf/dl-open.c | 35 +++++++++++- + elf/dl-support.c | 7 +++ + elf/dl-tls.c | 16 +++--- + elf/rtld.c | 1 + + posix/fork.c | 3 + + sysdeps/generic/ldsodefs.h | 9 ++- + sysdeps/pthread/Makefile | 10 +++- + sysdeps/pthread/tst-create1.c | 119 +++++++++++++++++++++++++++++++++++++++ + sysdeps/pthread/tst-create1mod.c | 41 ++++++++++++++ + 10 files changed, 235 insertions(+), 12 deletions(-) + create mode 100644 sysdeps/pthread/tst-create1.c + create mode 100644 sysdeps/pthread/tst-create1mod.c + +diff --git a/elf/dl-close.c b/elf/dl-close.c +index 93ff5c9..cfe0f1c 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -549,6 +549,9 @@ _dl_close_worker (struct link_map *map, bool force) + size_t tls_free_end; + tls_free_start = tls_free_end = NO_TLS_OFFSET; + ++ /* Protects global and module specitic TLS state. */ ++ __rtld_lock_lock_recursive (GL(dl_load_tls_lock)); ++ + /* We modify the list of loaded objects. */ + __rtld_lock_lock_recursive (GL(dl_load_write_lock)); + +@@ -784,6 +787,9 @@ _dl_close_worker (struct link_map *map, bool force) + GL(dl_tls_static_used) = tls_free_start; + } + ++ /* TLS is cleaned up for the unloaded modules. */ ++ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); ++ + #ifdef SHARED + /* Auditing checkpoint: we have deleted all objects. */ + if (__glibc_unlikely (do_audit)) +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 5295e93..6ea5dd2 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -66,6 +66,9 @@ struct dl_open_args + libc_map value in the namespace in case of a dlopen failure. */ + bool libc_already_loaded; + ++ /* Set to true if the end of dl_open_worker_begin was reached. */ ++ bool worker_continue; ++ + /* Original parameters to the program and the current environment. */ + int argc; + char **argv; +@@ -482,7 +485,7 @@ call_dl_init (void *closure) + } + + static void +-dl_open_worker (void *a) ++dl_open_worker_begin (void *a) + { + struct dl_open_args *args = a; + const char *file = args->file; +@@ -774,6 +777,36 @@ dl_open_worker (void *a) + _dl_call_libc_early_init (libc_map, false); + } + ++ args->worker_continue = true; ++} ++ ++static void ++dl_open_worker (void *a) ++{ ++ struct dl_open_args *args = a; ++ ++ args->worker_continue = false; ++ ++ { ++ /* Protects global and module specific TLS state. */ ++ __rtld_lock_lock_recursive (GL(dl_load_tls_lock)); ++ ++ struct dl_exception ex; ++ int err = _dl_catch_exception (&ex, dl_open_worker_begin, args); ++ ++ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); ++ ++ if (__glibc_unlikely (ex.errstring != NULL)) ++ /* Reraise the error. */ ++ _dl_signal_exception (err, &ex, NULL); ++ } ++ ++ if (!args->worker_continue) ++ return; ++ ++ int mode = args->mode; ++ struct link_map *new = args->map; ++ + /* Run the initializer functions of new objects. Temporarily + disable the exception handler, so that lazy binding failures are + fatal. */ +diff --git a/elf/dl-support.c b/elf/dl-support.c +index 02e2ed7..d99c1f1 100644 +--- a/elf/dl-support.c ++++ b/elf/dl-support.c +@@ -228,6 +228,13 @@ __rtld_lock_define_initialized_recursive (, _dl_load_lock) + list of loaded objects while an object is added to or removed from + that list. */ + __rtld_lock_define_initialized_recursive (, _dl_load_write_lock) ++ /* This lock protects global and module specific TLS related data. ++ E.g. it is held in dlopen and dlclose when GL(dl_tls_generation), ++ GL(dl_tls_max_dtv_idx) or GL(dl_tls_dtv_slotinfo_list) are ++ accessed and when TLS related relocations are processed for a ++ module. It was introduced to keep pthread_create accessing TLS ++ state that is being set up. */ ++__rtld_lock_define_initialized_recursive (, _dl_load_tls_lock) + + + #ifdef HAVE_AUX_VECTOR +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index d554ae4..9260d2d 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -532,7 +532,7 @@ _dl_allocate_tls_init (void *result) + size_t maxgen = 0; + + /* Protects global dynamic TLS related state. */ +- __rtld_lock_lock_recursive (GL(dl_load_lock)); ++ __rtld_lock_lock_recursive (GL(dl_load_tls_lock)); + + /* Check if the current dtv is big enough. */ + if (dtv[-1].counter < GL(dl_tls_max_dtv_idx)) +@@ -606,7 +606,7 @@ _dl_allocate_tls_init (void *result) + listp = listp->next; + assert (listp != NULL); + } +- __rtld_lock_unlock_recursive (GL(dl_load_lock)); ++ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); + + /* The DTV version is up-to-date now. */ + dtv[0].counter = maxgen; +@@ -745,7 +745,7 @@ _dl_update_slotinfo (unsigned long int req_modid) + + Here the dtv needs to be updated to new_gen generation count. + +- This code may be called during TLS access when GL(dl_load_lock) ++ This code may be called during TLS access when GL(dl_load_tls_lock) + is not held. In that case the user code has to synchronize with + dlopen and dlclose calls of relevant modules. A module m is + relevant if the generation of m <= new_gen and dlclose of m is +@@ -867,11 +867,11 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map) + if (__glibc_unlikely (the_map->l_tls_offset + != FORCED_DYNAMIC_TLS_OFFSET)) + { +- __rtld_lock_lock_recursive (GL(dl_load_lock)); ++ __rtld_lock_lock_recursive (GL(dl_load_tls_lock)); + if (__glibc_likely (the_map->l_tls_offset == NO_TLS_OFFSET)) + { + the_map->l_tls_offset = FORCED_DYNAMIC_TLS_OFFSET; +- __rtld_lock_unlock_recursive (GL(dl_load_lock)); ++ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); + } + else if (__glibc_likely (the_map->l_tls_offset + != FORCED_DYNAMIC_TLS_OFFSET)) +@@ -883,7 +883,7 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map) + #else + # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" + #endif +- __rtld_lock_unlock_recursive (GL(dl_load_lock)); ++ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); + + dtv[GET_ADDR_MODULE].pointer.to_free = NULL; + dtv[GET_ADDR_MODULE].pointer.val = p; +@@ -891,7 +891,7 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map) + return (char *) p + GET_ADDR_OFFSET; + } + else +- __rtld_lock_unlock_recursive (GL(dl_load_lock)); ++ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); + } + struct dtv_pointer result = allocate_and_init (the_map); + dtv[GET_ADDR_MODULE].pointer = result; +@@ -962,7 +962,7 @@ _dl_tls_get_addr_soft (struct link_map *l) + return NULL; + + dtv_t *dtv = THREAD_DTV (); +- /* This may be called without holding the GL(dl_load_lock). Reading ++ /* This may be called without holding the GL(dl_load_tls_lock). Reading + arbitrary gen value is fine since this is best effort code. */ + size_t gen = atomic_load_relaxed (&GL(dl_tls_generation)); + if (__glibc_unlikely (dtv[0].counter != gen)) +diff --git a/elf/rtld.c b/elf/rtld.c +index 8d2bba3..9642eb9 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -322,6 +322,7 @@ struct rtld_global _rtld_global = + #ifdef _LIBC_REENTRANT + ._dl_load_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER, + ._dl_load_write_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER, ++ ._dl_load_tls_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER, + #endif + ._dl_nns = 1, + ._dl_ns = +diff --git a/posix/fork.c b/posix/fork.c +index c471f7b..021691b 100644 +--- a/posix/fork.c ++++ b/posix/fork.c +@@ -99,6 +99,9 @@ __libc_fork (void) + /* Reset the lock the dynamic loader uses to protect its data. */ + __rtld_lock_initialize (GL(dl_load_lock)); + ++ /* Reset the lock protecting dynamic TLS related data. */ ++ __rtld_lock_initialize (GL(dl_load_tls_lock)); ++ + reclaim_stacks (); + + /* Run the handlers registered for the child. */ +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index d49529d..9ec1511 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -369,6 +369,13 @@ struct rtld_global + list of loaded objects while an object is added to or removed + from that list. */ + __rtld_lock_define_recursive (EXTERN, _dl_load_write_lock) ++ /* This lock protects global and module specific TLS related data. ++ E.g. it is held in dlopen and dlclose when GL(dl_tls_generation), ++ GL(dl_tls_max_dtv_idx) or GL(dl_tls_dtv_slotinfo_list) are ++ accessed and when TLS related relocations are processed for a ++ module. It was introduced to keep pthread_create accessing TLS ++ state that is being set up. */ ++ __rtld_lock_define_recursive (EXTERN, _dl_load_tls_lock) + + /* Incremented whenever something may have been added to dl_loaded. */ + EXTERN unsigned long long _dl_load_adds; +@@ -1268,7 +1275,7 @@ extern int _dl_scope_free (void *) attribute_hidden; + + /* Add module to slot information data. If DO_ADD is false, only the + required memory is allocated. Must be called with GL +- (dl_load_lock) acquired. If the function has already been called ++ (dl_load_tls_lock) acquired. If the function has already been called + for the link map L with !do_add, then this function will not raise + an exception, otherwise it is possible that it encounters a memory + allocation failure. */ +diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile +index 0af9c59..df8943f 100644 +--- a/sysdeps/pthread/Makefile ++++ b/sysdeps/pthread/Makefile +@@ -152,15 +152,17 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx6 tst-cancelx8 tst-cancelx9 \ + tst-cleanupx0 tst-cleanupx1 tst-cleanupx2 tst-cleanupx3 + + ifeq ($(build-shared),yes) +-tests += tst-atfork2 tst-pt-tls4 tst-_res1 tst-fini1 ++tests += tst-atfork2 tst-pt-tls4 tst-_res1 tst-fini1 tst-create1 + tests-nolibpthread += tst-fini1 + endif + + modules-names += tst-atfork2mod tst-tls4moda tst-tls4modb \ +- tst-_res1mod1 tst-_res1mod2 tst-fini1mod ++ tst-_res1mod1 tst-_res1mod2 tst-fini1mod \ ++ tst-create1mod + test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names))) + + tst-atfork2mod.so-no-z-defs = yes ++tst-create1mod.so-no-z-defs = yes + + ifeq ($(build-shared),yes) + # Build all the modules even when not actually running test programs. +@@ -279,4 +281,8 @@ LDFLAGS-tst-join7mod.so = -Wl,-soname,tst-join7mod.so + + CFLAGS-tst-unwind-thread.c += -funwind-tables + ++LDFLAGS-tst-create1 = -Wl,-export-dynamic ++$(objpfx)tst-create1: $(shared-thread-library) ++$(objpfx)tst-create1.out: $(objpfx)tst-create1mod.so ++ + endif +diff --git a/sysdeps/pthread/tst-create1.c b/sysdeps/pthread/tst-create1.c +new file mode 100644 +index 0000000..932586c +--- /dev/null ++++ b/sysdeps/pthread/tst-create1.c +@@ -0,0 +1,119 @@ ++/* Verify that pthread_create does not deadlock when ctors take locks. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++ ++/* ++Check if ctor and pthread_create deadlocks in ++ ++thread 1: dlopen -> ctor -> lock(user_lock) ++thread 2: lock(user_lock) -> pthread_create ++ ++or in ++ ++thread 1: dlclose -> dtor -> lock(user_lock) ++thread 2: lock(user_lock) -> pthread_create ++*/ ++ ++static pthread_barrier_t bar_ctor; ++static pthread_barrier_t bar_dtor; ++static pthread_mutex_t user_lock = PTHREAD_MUTEX_INITIALIZER; ++ ++void ++ctor (void) ++{ ++ xpthread_barrier_wait (&bar_ctor); ++ dprintf (1, "thread 1: in ctor: started.\n"); ++ xpthread_mutex_lock (&user_lock); ++ dprintf (1, "thread 1: in ctor: locked user_lock.\n"); ++ xpthread_mutex_unlock (&user_lock); ++ dprintf (1, "thread 1: in ctor: unlocked user_lock.\n"); ++ dprintf (1, "thread 1: in ctor: done.\n"); ++} ++ ++void ++dtor (void) ++{ ++ xpthread_barrier_wait (&bar_dtor); ++ dprintf (1, "thread 1: in dtor: started.\n"); ++ xpthread_mutex_lock (&user_lock); ++ dprintf (1, "thread 1: in dtor: locked user_lock.\n"); ++ xpthread_mutex_unlock (&user_lock); ++ dprintf (1, "thread 1: in dtor: unlocked user_lock.\n"); ++ dprintf (1, "thread 1: in dtor: done.\n"); ++} ++ ++static void * ++thread3 (void *a) ++{ ++ dprintf (1, "thread 3: started.\n"); ++ dprintf (1, "thread 3: done.\n"); ++ return 0; ++} ++ ++static void * ++thread2 (void *a) ++{ ++ pthread_t t3; ++ dprintf (1, "thread 2: started.\n"); ++ ++ xpthread_mutex_lock (&user_lock); ++ dprintf (1, "thread 2: locked user_lock.\n"); ++ xpthread_barrier_wait (&bar_ctor); ++ t3 = xpthread_create (0, thread3, 0); ++ xpthread_mutex_unlock (&user_lock); ++ dprintf (1, "thread 2: unlocked user_lock.\n"); ++ xpthread_join (t3); ++ ++ xpthread_mutex_lock (&user_lock); ++ dprintf (1, "thread 2: locked user_lock.\n"); ++ xpthread_barrier_wait (&bar_dtor); ++ t3 = xpthread_create (0, thread3, 0); ++ xpthread_mutex_unlock (&user_lock); ++ dprintf (1, "thread 2: unlocked user_lock.\n"); ++ xpthread_join (t3); ++ ++ dprintf (1, "thread 2: done.\n"); ++ return 0; ++} ++ ++static void ++thread1 (void) ++{ ++ dprintf (1, "thread 1: started.\n"); ++ xpthread_barrier_init (&bar_ctor, NULL, 2); ++ xpthread_barrier_init (&bar_dtor, NULL, 2); ++ pthread_t t2 = xpthread_create (0, thread2, 0); ++ void *p = xdlopen ("tst-create1mod.so", RTLD_NOW | RTLD_GLOBAL); ++ dprintf (1, "thread 1: dlopen done.\n"); ++ xdlclose (p); ++ dprintf (1, "thread 1: dlclose done.\n"); ++ xpthread_join (t2); ++ dprintf (1, "thread 1: done.\n"); ++} ++ ++static int ++do_test (void) ++{ ++ thread1 (); ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/pthread/tst-create1mod.c b/sysdeps/pthread/tst-create1mod.c +new file mode 100644 +index 0000000..62c9006 +--- /dev/null ++++ b/sysdeps/pthread/tst-create1mod.c +@@ -0,0 +1,41 @@ ++/* Verify that pthread_create does not deadlock when ctors take locks. ++ 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 ++ . */ ++ ++#include ++ ++/* Require TLS setup for the module. */ ++__thread int tlsvar; ++ ++void ctor (void); ++void dtor (void); ++ ++static void __attribute__ ((constructor)) ++do_init (void) ++{ ++ dprintf (1, "constructor started: %d.\n", tlsvar++); ++ ctor (); ++ dprintf (1, "constructor done: %d.\n", tlsvar++); ++} ++ ++static void __attribute__ ((destructor)) ++do_end (void) ++{ ++ dprintf (1, "destructor started: %d.\n", tlsvar++); ++ dtor (); ++ dprintf (1, "destructor done: %d.\n", tlsvar++); ++} +-- +1.8.3.1 + diff --git a/elf-Drop-elf-tls-macros.h-in-favor-of-__thread-and-t.patch b/elf-Drop-elf-tls-macros.h-in-favor-of-__thread-and-t.patch new file mode 100644 index 0000000000000000000000000000000000000000..1cd2fc280e6a7daac32beacfe9a102737dffb986 --- /dev/null +++ b/elf-Drop-elf-tls-macros.h-in-favor-of-__thread-and-t.patch @@ -0,0 +1,543 @@ +From 33c50ef42878b07ee6ead8b3f1a81d8c2c74697c Mon Sep 17 00:00:00 2001 +From: Fangrui Song +Date: Mon, 16 Aug 2021 09:59:30 -0700 +Subject: [PATCH] elf: Drop elf/tls-macros.h in favor of __thread and tls_model + attributes [BZ #28152] [BZ #28205] + +elf/tls-macros.h was added for TLS testing when GCC did not support +__thread. __thread and tls_model attributes are mature now and have been +used by many newer tests. + +Also delete tst-tls2.c which tests .tls_common (unused by modern GCC and +unsupported by Clang/LLD). .tls_common and .tbss definition are almost +identical after linking, so the runtime test doesn't add additional +coverage. Assembler and linker tests should be on the binutils side. + +When LLD 13.0.0 is allowed in configure.ac +(https://sourceware.org/pipermail/libc-alpha/2021-August/129866.html), +`make check` result is on par with glibc built with GNU ld on aarch64 +and x86_64. + +As a future clean-up, TLS_GD/TLS_LD/TLS_IE/TLS_IE macros can be removed from +sysdeps/*/tls-macros.h. We can add optional -mtls-dialect={gnu2,trad} +tests to ensure coverage. + +Tested on aarch64-linux-gnu, powerpc64le-linux-gnu, and x86_64-linux-gnu. + +Reviewed-by: Szabolcs Nagy +--- + elf/Makefile | 4 +- + elf/tls-macros.h | 25 ----------- + elf/tst-tls1.c | 64 +++++++++++----------------- + elf/tst-tls2.c | 82 ------------------------------------ + elf/tst-tls3.c | 26 +++++------- + elf/tst-tlsmod1.c | 24 +++++------ + elf/tst-tlsmod2.c | 6 +-- + elf/tst-tlsmod3.c | 8 ++-- + elf/tst-tlsmod4.c | 6 +-- + elf/tst-tlsmod5.c | 4 +- + elf/tst-tlsmod6.c | 4 +- + sysdeps/powerpc/mod-tlsopt-powerpc.c | 6 +-- + sysdeps/powerpc/tst-tlsifunc.c | 4 +- + 13 files changed, 64 insertions(+), 199 deletions(-) + delete mode 100644 elf/tls-macros.h + delete mode 100644 elf/tst-tls2.c + +diff --git a/elf/Makefile b/elf/Makefile +index d05f410..725537c 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -163,7 +163,7 @@ tests-static-normal := tst-array1-static tst-array5-static \ + tst-single_threaded-static tst-single_threaded-pthread-static \ + tst-dst-static tst-getauxval-static + +-tests-static-internal := tst-tls1-static tst-tls2-static \ ++tests-static-internal := tst-tls1-static \ + tst-ptrguard1-static tst-stackguard1-static \ + tst-tls1-static-non-pie + +@@ -183,7 +183,7 @@ endif + tests := tst-tls9 tst-leaks1 \ + tst-array1 tst-array2 tst-array3 tst-array4 tst-array5 \ + tst-auxv tst-stringtable +-tests-internal := tst-tls1 tst-tls2 $(tests-static-internal) ++tests-internal := tst-tls1 $(tests-static-internal) + tests-static := $(tests-static-normal) $(tests-static-internal) + + ifeq (yes,$(build-shared)) +diff --git a/elf/tls-macros.h b/elf/tls-macros.h +deleted file mode 100644 +index e25e33b..0000000 +--- a/elf/tls-macros.h ++++ /dev/null +@@ -1,25 +0,0 @@ +-/* Macros to support TLS testing in times of missing compiler support. */ +- +-#define COMMON_INT_DEF(x) \ +- asm (".tls_common " #x ",4,4") +-/* XXX Until we get compiler support we don't need declarations. */ +-#define COMMON_INT_DECL(x) +- +-/* XXX This definition will probably be machine specific, too. */ +-#define VAR_INT_DEF(x) \ +- asm (".section .tdata\n\t" \ +- ".globl " #x "\n" \ +- ".balign 4\n" \ +- #x ":\t.long 0\n\t" \ +- ".size " #x ",4\n\t" \ +- ".previous") +-/* XXX Until we get compiler support we don't need declarations. */ +-#define VAR_INT_DECL(x) +- +-#include_next +- +- /* XXX Each architecture must have its own asm for now. */ +-#if !defined TLS_LE || !defined TLS_IE \ +- || !defined TLS_LD || !defined TLS_GD +-# error "No support for this architecture so far." +-#endif +diff --git a/elf/tst-tls1.c b/elf/tst-tls1.c +index c31da56..b341221 100644 +--- a/elf/tst-tls1.c ++++ b/elf/tst-tls1.c +@@ -1,13 +1,14 @@ + /* glibc test for TLS in ld.so. */ + #include + +-#include "tls-macros.h" +- +- +-/* Two common 'int' variables in TLS. */ +-COMMON_INT_DEF(foo); +-COMMON_INT_DEF(bar); + ++__thread int foo, bar __attribute__ ((tls_model("local-exec"))); ++extern __thread int foo_gd asm ("foo") __attribute__ ((tls_model("global-dynamic"))); ++extern __thread int foo_ld asm ("foo") __attribute__ ((tls_model("local-dynamic"))); ++extern __thread int foo_ie asm ("foo") __attribute__ ((tls_model("initial-exec"))); ++extern __thread int bar_gd asm ("bar") __attribute__ ((tls_model("global-dynamic"))); ++extern __thread int bar_ld asm ("bar") __attribute__ ((tls_model("local-dynamic"))); ++extern __thread int bar_ie asm ("bar") __attribute__ ((tls_model("initial-exec"))); + + static int + do_test (void) +@@ -18,63 +19,48 @@ do_test (void) + + /* Set the variable using the local exec model. */ + puts ("set bar to 1 (LE)"); +- ap = TLS_LE (bar); +- *ap = 1; ++ bar = 1; + + + /* Get variables using initial exec model. */ + fputs ("get sum of foo and bar (IE)", stdout); +- ap = TLS_IE (foo); +- bp = TLS_IE (bar); ++ ap = &foo_ie; ++ bp = &bar_ie; + printf (" = %d\n", *ap + *bp); + result |= *ap + *bp != 1; +- if (*ap != 0) +- { +- printf ("foo = %d\n", *ap); +- result = 1; +- } +- if (*bp != 1) ++ if (*ap != 0 || *bp != 1) + { +- printf ("bar = %d\n", *bp); ++ printf ("foo = %d\nbar = %d\n", *ap, *bp); + result = 1; + } + + +- /* Get variables using local dynamic model. */ +- fputs ("get sum of foo and bar (LD)", stdout); +- ap = TLS_LD (foo); +- bp = TLS_LD (bar); ++ /* Get variables using local dynamic model or TLSDESC. */ ++ fputs ("get sum of foo and bar (LD or TLSDESC)", stdout); ++ ap = &foo_ld; ++ bp = &bar_ld; + printf (" = %d\n", *ap + *bp); + result |= *ap + *bp != 1; +- if (*ap != 0) +- { +- printf ("foo = %d\n", *ap); +- result = 1; +- } +- if (*bp != 1) ++ if (*ap != 0 || *bp != 1) + { +- printf ("bar = %d\n", *bp); ++ printf ("foo = %d\nbar = %d\n", *ap, *bp); + result = 1; + } + + +- /* Get variables using generic dynamic model. */ +- fputs ("get sum of foo and bar (GD)", stdout); +- ap = TLS_GD (foo); +- bp = TLS_GD (bar); ++ /* Get variables using general dynamic model or TLSDESC. */ ++ fputs ("get sum of foo and bar (GD or TLSDESC)", stdout); ++ ap = &foo_gd; ++ bp = &bar_gd; + printf (" = %d\n", *ap + *bp); + result |= *ap + *bp != 1; +- if (*ap != 0) +- { +- printf ("foo = %d\n", *ap); +- result = 1; +- } +- if (*bp != 1) ++ if (*ap != 0 || *bp != 1) + { +- printf ("bar = %d\n", *bp); ++ printf ("foo = %d\nbar = %d\n", *ap, *bp); + result = 1; + } + ++ + return result; + } + +diff --git a/elf/tst-tls2.c b/elf/tst-tls2.c +deleted file mode 100644 +index 963b8d6..0000000 +--- a/elf/tst-tls2.c ++++ /dev/null +@@ -1,82 +0,0 @@ +-/* glibc test for TLS in ld.so. */ +-#include +- +-#include "tls-macros.h" +- +- +-/* Two 'int' variables in TLS. */ +-VAR_INT_DEF(foo); +-VAR_INT_DEF(bar); +- +- +-static int +-do_test (void) +-{ +- int result = 0; +- int *ap, *bp; +- +- +- /* Set the variable using the local exec model. */ +- puts ("set bar to 1 (LE)"); +- ap = TLS_LE (bar); +- *ap = 1; +- +- +- /* Get variables using initial exec model. */ +- fputs ("get sum of foo and bar (IE)", stdout); +- ap = TLS_IE (foo); +- bp = TLS_IE (bar); +- printf (" = %d\n", *ap + *bp); +- result |= *ap + *bp != 1; +- if (*ap != 0) +- { +- printf ("foo = %d\n", *ap); +- result = 1; +- } +- if (*bp != 1) +- { +- printf ("bar = %d\n", *bp); +- result = 1; +- } +- +- +- /* Get variables using local dynamic model. */ +- fputs ("get sum of foo and bar (LD)", stdout); +- ap = TLS_LD (foo); +- bp = TLS_LD (bar); +- printf (" = %d\n", *ap + *bp); +- result |= *ap + *bp != 1; +- if (*ap != 0) +- { +- printf ("foo = %d\n", *ap); +- result = 1; +- } +- if (*bp != 1) +- { +- printf ("bar = %d\n", *bp); +- result = 1; +- } +- +- +- /* Get variables using generic dynamic model. */ +- fputs ("get sum of foo and bar (GD)", stdout); +- ap = TLS_GD (foo); +- bp = TLS_GD (bar); +- printf (" = %d\n", *ap + *bp); +- result |= *ap + *bp != 1; +- if (*ap != 0) +- { +- printf ("foo = %d\n", *ap); +- result = 1; +- } +- if (*bp != 1) +- { +- printf ("bar = %d\n", *bp); +- result = 1; +- } +- +- return result; +-} +- +- +-#include +diff --git a/elf/tst-tls3.c b/elf/tst-tls3.c +index 7e0abb4..222b179 100644 +--- a/elf/tst-tls3.c ++++ b/elf/tst-tls3.c +@@ -1,13 +1,12 @@ + /* glibc test for TLS in ld.so. */ + #include + +-#include "tls-macros.h" + +- +-/* One define int variable, two externs. */ +-COMMON_INT_DECL(foo); +-VAR_INT_DECL(bar); +-VAR_INT_DEF(baz); ++__thread int foo, bar __attribute__ ((tls_model("initial-exec"))); ++__thread int baz __attribute__ ((tls_model("local-exec"))); ++extern __thread int foo_gd __attribute__ ((alias("foo"), tls_model("global-dynamic"))); ++extern __thread int bar_gd __attribute__ ((alias("bar"), tls_model("global-dynamic"))); ++extern __thread int baz_ld __attribute__ ((alias("baz"), tls_model("local-dynamic"))); + + + extern int in_dso (void); +@@ -22,23 +21,20 @@ do_test (void) + + /* Set the variable using the local exec model. */ + puts ("set baz to 3 (LE)"); +- ap = TLS_LE (baz); +- *ap = 3; ++ baz = 3; + + + /* Get variables using initial exec model. */ + puts ("set variables foo and bar (IE)"); +- ap = TLS_IE (foo); +- *ap = 1; +- bp = TLS_IE (bar); +- *bp = 2; ++ foo = 1; ++ bar = 2; + + + /* Get variables using local dynamic model. */ + fputs ("get sum of foo, bar (GD) and baz (LD)", stdout); +- ap = TLS_GD (foo); +- bp = TLS_GD (bar); +- cp = TLS_LD (baz); ++ ap = &foo_gd; ++ bp = &bar_gd; ++ cp = &baz_ld; + printf (" = %d\n", *ap + *bp + *cp); + result |= *ap + *bp + *cp != 6; + if (*ap != 1) +diff --git a/elf/tst-tlsmod1.c b/elf/tst-tlsmod1.c +index 8d91567..a448c4d 100644 +--- a/elf/tst-tlsmod1.c ++++ b/elf/tst-tlsmod1.c +@@ -1,12 +1,12 @@ + #include + +-#include "tls-macros.h" + ++__thread int foo, bar __attribute__ ((tls_model("global-dynamic"))); ++extern __thread int baz __attribute__ ((tls_model("global-dynamic"))); ++extern __thread int foo_ie asm ("foo") __attribute__ ((tls_model("initial-exec"))); ++extern __thread int bar_ie asm ("bar") __attribute__ ((tls_model("initial-exec"))); ++extern __thread int baz_ie asm ("baz") __attribute__ ((tls_model("initial-exec"))); + +-/* One define int variable, two externs. */ +-COMMON_INT_DEF(foo); +-VAR_INT_DEF(bar); +-VAR_INT_DECL(baz); + + extern int in_dso (void); + +@@ -19,8 +19,8 @@ in_dso (void) + /* Get variables using initial exec model. */ + fputs ("get sum of foo and bar (IE)", stdout); + asm ("" ::: "memory"); +- ap = TLS_IE (foo); +- bp = TLS_IE (bar); ++ ap = &foo_ie; ++ bp = &bar_ie; + printf (" = %d\n", *ap + *bp); + result |= *ap + *bp != 3; + if (*ap != 1) +@@ -35,11 +35,11 @@ in_dso (void) + } + + +- /* Get variables using generic dynamic model. */ +- fputs ("get sum of foo and bar and baz (GD)", stdout); +- ap = TLS_GD (foo); +- bp = TLS_GD (bar); +- cp = TLS_GD (baz); ++ /* Get variables using generic dynamic model or TLSDESC. */ ++ fputs ("get sum of foo and bar and baz (GD or TLSDESC)", stdout); ++ ap = &foo; ++ bp = &bar; ++ cp = &baz; + printf (" = %d\n", *ap + *bp + *cp); + result |= *ap + *bp + *cp != 6; + if (*ap != 1) +diff --git a/elf/tst-tlsmod2.c b/elf/tst-tlsmod2.c +index 40eb140..3223fe4 100644 +--- a/elf/tst-tlsmod2.c ++++ b/elf/tst-tlsmod2.c +@@ -1,9 +1,7 @@ + #include + +-#include "tls-macros.h" + +- +-COMMON_INT_DEF(foo); ++__thread int foo; + + + int +@@ -15,7 +13,7 @@ in_dso (int n, int *caller_foop) + puts ("foo"); /* Make sure PLT is used before macros. */ + asm ("" ::: "memory"); + +- foop = TLS_GD (foo); ++ foop = &foo; + + if (caller_foop != NULL && foop != caller_foop) + { +diff --git a/elf/tst-tlsmod3.c b/elf/tst-tlsmod3.c +index 6d186c4..d6e7498 100644 +--- a/elf/tst-tlsmod3.c ++++ b/elf/tst-tlsmod3.c +@@ -1,10 +1,10 @@ + #include + +-#include "tls-macros.h" + + extern int in_dso (int n, int *caller_foop); + +-COMMON_INT_DEF(comm_n); ++extern __thread int foo; ++__thread int comm_n; + + + +@@ -20,8 +20,8 @@ in_dso2 (void) + puts ("foo"); /* Make sure PLT is used before macros. */ + asm ("" ::: "memory"); + +- foop = TLS_GD (foo); +- np = TLS_GD (comm_n); ++ foop = &foo; ++ np = &comm_n; + + if (n != *np) + { +diff --git a/elf/tst-tlsmod4.c b/elf/tst-tlsmod4.c +index 86889aa..f38919a 100644 +--- a/elf/tst-tlsmod4.c ++++ b/elf/tst-tlsmod4.c +@@ -1,9 +1,7 @@ + #include + +-#include "tls-macros.h" + +- +-COMMON_INT_DEF(baz); ++__thread int baz; + + + int +@@ -15,7 +13,7 @@ in_dso (int n, int *caller_bazp) + puts ("foo"); /* Make sure PLT is used before macros. */ + asm ("" ::: "memory"); + +- bazp = TLS_GD (baz); ++ bazp = &baz; + + if (caller_bazp != NULL && bazp != caller_bazp) + { +diff --git a/elf/tst-tlsmod5.c b/elf/tst-tlsmod5.c +index a97c7e5..3f39c5b 100644 +--- a/elf/tst-tlsmod5.c ++++ b/elf/tst-tlsmod5.c +@@ -1,3 +1 @@ +-#include "tls-macros.h" +- +-COMMON_INT_DEF(foo); ++__thread int foo; +diff --git a/elf/tst-tlsmod6.c b/elf/tst-tlsmod6.c +index e968596..7b3571f 100644 +--- a/elf/tst-tlsmod6.c ++++ b/elf/tst-tlsmod6.c +@@ -1,3 +1 @@ +-#include "tls-macros.h" +- +-COMMON_INT_DEF(bar); ++__thread int bar; +diff --git a/sysdeps/powerpc/mod-tlsopt-powerpc.c b/sysdeps/powerpc/mod-tlsopt-powerpc.c +index ee0db12..2a82e53 100644 +--- a/sysdeps/powerpc/mod-tlsopt-powerpc.c ++++ b/sysdeps/powerpc/mod-tlsopt-powerpc.c +@@ -1,11 +1,9 @@ + /* shared library to test for __tls_get_addr optimization. */ + #include + +-#include "../../elf/tls-macros.h" + #include "dl-tls.h" + +-/* common 'int' variable in TLS. */ +-COMMON_INT_DEF(foo); ++__thread int foo __attribute__ ((tls_model("global-dynamic"))); + + + int +@@ -14,7 +12,7 @@ tls_get_addr_opt_test (void) + int result = 0; + + /* Get variable using general dynamic model. */ +- int *ap = TLS_GD (foo); ++ int *ap = &foo; + if (*ap != 0) + { + printf ("foo = %d\n", *ap); +diff --git a/sysdeps/powerpc/tst-tlsifunc.c b/sysdeps/powerpc/tst-tlsifunc.c +index 3095d41..c8c0bad 100644 +--- a/sysdeps/powerpc/tst-tlsifunc.c ++++ b/sysdeps/powerpc/tst-tlsifunc.c +@@ -21,9 +21,9 @@ + #include + #include + #include +-#include + + __thread int bar; ++extern __thread int bar_gd asm ("bar") __attribute__ ((tls_model("global-dynamic"))); + static int *bar_ptr = NULL; + + static uint32_t resolver_platform = 0; +@@ -57,7 +57,7 @@ get_platform (void) + void + init_foo (void) + { +- bar_ptr = TLS_GD (bar); ++ bar_ptr = &bar_gd; + } + + int +-- +1.8.3.1 + diff --git a/elf-Earlier-missing-dynamic-segment-check-in-_dl_map.patch b/elf-Earlier-missing-dynamic-segment-check-in-_dl_map.patch new file mode 100644 index 0000000000000000000000000000000000000000..3d5bd609c9379ddf8f0b18d0a463c03cafe1e94c --- /dev/null +++ b/elf-Earlier-missing-dynamic-segment-check-in-_dl_map.patch @@ -0,0 +1,73 @@ +From ea32ec354c65ddad11b82ca9d057010df13a9cea Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 5 Nov 2021 17:01:24 +0100 +Subject: [PATCH] elf: Earlier missing dynamic segment check in + _dl_map_object_from_fd + +Separated debuginfo files have PT_DYNAMIC with p_filesz == 0. We +need to check for that before the _dl_map_segments call because +that could attempt to write to mappings that extend beyond the end +of the file, resulting in SIGBUS. + +Reviewed-by: H.J. Lu +--- + elf/dl-load.c | 22 ++++++++++++---------- + 1 file changed, 12 insertions(+), 10 deletions(-) + +diff --git a/elf/dl-load.c b/elf/dl-load.c +index a1f1682..9f4fa96 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -1135,6 +1135,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + struct loadcmd loadcmds[l->l_phnum]; + size_t nloadcmds = 0; + bool has_holes = false; ++ bool empty_dynamic = false; + + /* The struct is initialized to zero so this is not necessary: + l->l_ld = 0; +@@ -1147,7 +1148,9 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + segments are mapped in. We record the addresses it says + verbatim, and later correct for the run-time load address. */ + case PT_DYNAMIC: +- if (ph->p_filesz) ++ if (ph->p_filesz == 0) ++ empty_dynamic = true; /* Usually separate debuginfo. */ ++ else + { + /* Debuginfo only files from "objcopy --only-keep-debug" + contain a PT_DYNAMIC segment with p_filesz == 0. Skip +@@ -1270,6 +1273,13 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + goto lose; + } + ++ /* This check recognizes most separate debuginfo files. */ ++ if (__glibc_unlikely ((l->l_ld == 0 && type == ET_DYN) || empty_dynamic)) ++ { ++ errstring = N_("object file has no dynamic section"); ++ goto lose; ++ } ++ + /* Length of the sections to be loaded. */ + maplength = loadcmds[nloadcmds - 1].allocend - loadcmds[0].mapstart; + +@@ -1287,15 +1297,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + } + } + +- if (l->l_ld == 0) +- { +- if (__glibc_unlikely (type == ET_DYN)) +- { +- errstring = N_("object file has no dynamic section"); +- goto lose; +- } +- } +- else ++ if (l->l_ld != 0) + l->l_ld = (ElfW(Dyn) *) ((ElfW(Addr)) l->l_ld + l->l_addr); + + elf_get_dynamic_info (l); +-- +1.8.3.1 + diff --git a/elf-Fix-missing-colon-in-LD_SHOW_AUXV-output-BZ-2825.patch b/elf-Fix-missing-colon-in-LD_SHOW_AUXV-output-BZ-2825.patch new file mode 100644 index 0000000000000000000000000000000000000000..ffd1cb1903f567190104c39dfda48188958932cb --- /dev/null +++ b/elf-Fix-missing-colon-in-LD_SHOW_AUXV-output-BZ-2825.patch @@ -0,0 +1,27 @@ +From 82fbcd7118d760492e2ecc9fa291e358b9ba0361 Mon Sep 17 00:00:00 2001 +From: Arjun Shankar +Date: Fri, 20 Aug 2021 16:24:05 +0200 +Subject: [PATCH] elf: Fix missing colon in LD_SHOW_AUXV output [BZ #28253] + +This commit adds a missing colon in the AT_MINSIGSTKSZ entry in +the _dl_show_auxv function. +--- + elf/dl-sysdep.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/elf/dl-sysdep.c b/elf/dl-sysdep.c +index d47bef1..2c684c2 100644 +--- a/elf/dl-sysdep.c ++++ b/elf/dl-sysdep.c +@@ -317,7 +317,7 @@ _dl_show_auxv (void) + [AT_SYSINFO_EHDR - 2] = { "SYSINFO_EHDR: 0x", hex }, + [AT_RANDOM - 2] = { "RANDOM: 0x", hex }, + [AT_HWCAP2 - 2] = { "HWCAP2: 0x", hex }, +- [AT_MINSIGSTKSZ - 2] = { "MINSIGSTKSZ ", dec }, ++ [AT_MINSIGSTKSZ - 2] = { "MINSIGSTKSZ: ", dec }, + [AT_L1I_CACHESIZE - 2] = { "L1I_CACHESIZE: ", dec }, + [AT_L1I_CACHEGEOMETRY - 2] = { "L1I_CACHEGEOMETRY: 0x", hex }, + [AT_L1D_CACHESIZE - 2] = { "L1D_CACHESIZE: ", dec }, +-- +1.8.3.1 + diff --git a/elf-Makefile-Reflow-and-sort-most-variable-assignmen.patch b/elf-Makefile-Reflow-and-sort-most-variable-assignmen.patch new file mode 100644 index 0000000000000000000000000000000000000000..1d1f790b4cba3aa16b78b4124e9cae79f59f9f24 --- /dev/null +++ b/elf-Makefile-Reflow-and-sort-most-variable-assignmen.patch @@ -0,0 +1,544 @@ +From de6cdd68753ed126a3ecf105d98e8c0ee8cb6ec4 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 14 Jan 2022 20:16:05 +0100 +Subject: [PATCH] elf/Makefile: Reflow and sort most variable assignments + +Reviewed-by: H.J. Lu +(cherry picked from commit 7de01e60c200c431d3469deb784da8fd4508fc15) +--- + elf/Makefile | 386 +++++++++++++++++++++++++++++++++++++++------------ + 1 file changed, 294 insertions(+), 92 deletions(-) + +diff --git a/elf/Makefile b/elf/Makefile +index 5859d47fc7..f930e04e27 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -21,21 +21,62 @@ subdir := elf + + include ../Makeconfig + +-headers = elf.h bits/elfclass.h link.h bits/link.h +-routines = $(all-dl-routines) dl-support dl-iteratephdr \ +- dl-addr dl-addr-obj enbl-secure dl-profstub \ +- dl-origin dl-libc dl-sym dl-sysdep dl-error \ +- dl-reloc-static-pie libc_early_init rtld_static_init ++headers = \ ++ bits/elfclass.h \ ++ bits/link.h \ ++ elf.h \ ++ link.h \ ++ # headers ++ ++routines = \ ++ $(all-dl-routines) \ ++ dl-addr \ ++ dl-addr-obj \ ++ dl-error \ ++ dl-iteratephdr \ ++ dl-libc \ ++ dl-origin \ ++ dl-profstub \ ++ dl-reloc-static-pie \ ++ dl-support \ ++ dl-sym \ ++ dl-sysdep \ ++ enbl-secure \ ++ libc_early_init \ ++ rtld_static_init \ ++ # routines + + # The core dynamic linking functions are in libc for the static and + # profiled libraries. +-dl-routines = $(addprefix dl-,load lookup object reloc deps \ +- runtime init fini debug misc \ +- version profile tls origin scope \ +- execstack open close trampoline \ +- exception sort-maps lookup-direct \ +- call-libc-early-init write \ +- thread_gscope_wait tls_init_tp) ++dl-routines = \ ++ dl-call-libc-early-init \ ++ dl-close \ ++ dl-debug \ ++ dl-deps \ ++ dl-exception \ ++ dl-execstack \ ++ dl-fini \ ++ dl-init \ ++ dl-load \ ++ dl-lookup \ ++ dl-lookup-direct \ ++ dl-misc \ ++ dl-object \ ++ dl-open \ ++ dl-origin \ ++ dl-profile \ ++ dl-reloc \ ++ dl-runtime \ ++ dl-scope \ ++ dl-sort-maps \ ++ dl-thread_gscope_wait \ ++ dl-tls \ ++ dl-tls_init_tp \ ++ dl-trampoline \ ++ dl-version \ ++ dl-write \ ++ # dl-routines ++ + ifeq (yes,$(use-ldconfig)) + dl-routines += dl-cache + endif +@@ -58,16 +99,38 @@ endif + + all-dl-routines = $(dl-routines) $(sysdep-dl-routines) + # But they are absent from the shared libc, because that code is in ld.so. +-elide-routines.os = $(all-dl-routines) dl-support enbl-secure dl-origin \ +- dl-sysdep dl-exception dl-reloc-static-pie \ +- thread_gscope_wait rtld_static_init ++elide-routines.os = \ ++ $(all-dl-routines) \ ++ dl-exception \ ++ dl-origin \ ++ dl-reloc-static-pie \ ++ dl-support \ ++ dl-sysdep \ ++ enbl-secure \ ++ rtld_static_init \ ++ thread_gscope_wait \ ++ # elide-routines.os + + # ld.so uses those routines, plus some special stuff for being the program + # interpreter and operating independent of libc. +-rtld-routines = rtld $(all-dl-routines) dl-sysdep dl-environ dl-minimal \ +- dl-error-minimal dl-conflict dl-hwcaps dl-hwcaps_split dl-hwcaps-subdirs \ +- dl-usage dl-diagnostics dl-diagnostics-kernel dl-diagnostics-cpu \ +- dl-mutex ++rtld-routines = \ ++ $(all-dl-routines) \ ++ dl-conflict \ ++ dl-diagnostics \ ++ dl-diagnostics-cpu \ ++ dl-diagnostics-kernel \ ++ dl-environ \ ++ dl-error-minimal \ ++ dl-hwcaps \ ++ dl-hwcaps-subdirs \ ++ dl-hwcaps_split \ ++ dl-minimal \ ++ dl-mutex \ ++ dl-sysdep \ ++ dl-usage \ ++ rtld \ ++ # rtld-routines ++ + all-rtld-routines = $(rtld-routines) $(sysdep-rtld-routines) + + CFLAGS-dl-runtime.c += -fexceptions -fasynchronous-unwind-tables +@@ -102,8 +165,16 @@ ld-map = $(common-objpfx)ld.map + endif + + ifeq (yes,$(build-shared)) +-extra-objs = $(all-rtld-routines:%=%.os) sofini.os interp.os +-generated += librtld.os dl-allobjs.os ld.so ldd ++extra-objs = \ ++ $(all-rtld-routines:%=%.os) \ ++ sofini.os \ ++ interp.os \ ++ # extra-objs ++generated += \ ++ dl-allobjs.os \ ++ ld.so ldd \ ++ librtld.os \ ++ # generated + install-others = $(inst_rtlddir)/$(rtld-installed-name) + install-bin-script = ldd + endif +@@ -121,8 +192,15 @@ others-static += ldconfig + others += ldconfig + install-rootsbin += ldconfig + +-ldconfig-modules := cache readlib xmalloc xstrdup chroot_canon static-stubs \ +- stringtable ++ldconfig-modules := \ ++ cache \ ++ chroot_canon \ ++ readlib \ ++ static-stubs \ ++ stringtable \ ++ xmalloc \ ++ xstrdup \ ++ # ldconfig-modules + extra-objs += $(ldconfig-modules:=.o) + others-extras = $(ldconfig-modules) + endif +@@ -156,23 +234,35 @@ $(inst_auditdir)/sotruss-lib.so: $(objpfx)sotruss-lib.so $(+force) + $(do-install-program) + endif + +-tests-static-normal := tst-array1-static tst-array5-static \ +- tst-dl-iter-static \ +- tst-tlsalign-static tst-tlsalign-extern-static \ +- tst-linkall-static tst-env-setuid tst-env-setuid-tunables \ +- tst-single_threaded-static tst-single_threaded-pthread-static \ +- tst-dst-static tst-getauxval-static +- +-tests-static-internal := tst-tls1-static \ +- tst-ptrguard1-static tst-stackguard1-static \ +- tst-tls1-static-non-pie ++tests-static-normal := \ ++ tst-array1-static \ ++ tst-array5-static \ ++ tst-dl-iter-static \ ++ tst-dst-static \ ++ tst-env-setuid \ ++ tst-env-setuid-tunables \ ++ tst-getauxval-static \ ++ tst-linkall-static \ ++ tst-single_threaded-pthread-static \ ++ tst-single_threaded-static \ ++ tst-tlsalign-extern-static \ ++ tst-tlsalign-static \ ++ # tests-static-normal ++ ++tests-static-internal := \ ++ tst-ptrguard1-static \ ++ tst-stackguard1-static \ ++ tst-tls1-static \ ++ tst-tls1-static-non-pie \ ++ # tests-static-internal + + CRT-tst-tls1-static-non-pie := $(csu-objpfx)crt1.o + tst-tls1-static-non-pie-no-pie = yes + + tests-container := \ +- tst-ldconfig-bad-aux-cache \ +- tst-ldconfig-ld_so_conf-update ++ tst-ldconfig-bad-aux-cache \ ++ tst-ldconfig-ld_so_conf-update \ ++ # tests-container + + ifeq (no,$(build-hardcoded-path-in-tests)) + # This is an ld.so.cache test, and RPATH/RUNPATH in the executable +@@ -180,14 +271,31 @@ ifeq (no,$(build-hardcoded-path-in-tests)) + tests-container += tst-glibc-hwcaps-prepend-cache + endif + +-tests := tst-tls9 tst-leaks1 \ +- tst-array1 tst-array2 tst-array3 tst-array4 tst-array5 \ +- tst-auxv tst-stringtable +-tests-internal := tst-tls1 $(tests-static-internal) ++tests := \ ++ tst-array1 \ ++ tst-array2 \ ++ tst-array3 \ ++ tst-array4 \ ++ tst-array5 \ ++ tst-auxv \ ++ tst-leaks1 \ ++ tst-stringtable \ ++ tst-tls9 \ ++ # tests ++ ++tests-internal := \ ++ $(tests-static-internal) \ ++ tst-tls1 \ ++ # tests-internal ++ + tests-static := $(tests-static-normal) $(tests-static-internal) + + ifeq (yes,$(build-shared)) +-tests-static += tst-tls9-static tst-single_threaded-static-dlopen ++tests-static += \ ++ tst-single_threaded-static-dlopen \ ++ tst-tls9-static \ ++ # tests-static ++ + static-dlopen-environment = \ + LD_LIBRARY_PATH=$(ld-library-path):$(common-objpfx)dlfcn + tst-tls9-static-ENV = $(static-dlopen-environment) +@@ -312,33 +421,65 @@ tests += \ + unload6 \ + unload7 \ + unload8 \ +-# reldep9 ++ # tests + tests-cxx = \ + tst-dlopen-nodelete-reloc \ + tst-nodelete \ + tst-unique3 \ + tst-unique4 \ +-# tests-cxx ++ # tests-cxx + + tests += $(if $(CXX),$(tests-cxx)) +-tests-internal += loadtest unload unload2 circleload1 \ +- neededtest neededtest2 neededtest3 neededtest4 \ +- tst-tls3 tst-tls6 tst-tls7 tst-tls8 tst-dlmopen2 \ +- tst-ptrguard1 tst-stackguard1 \ +- tst-create_format1 tst-tls-surplus tst-dl-hwcaps_split +-tests-container += tst-pldd tst-dlopen-tlsmodid-container \ +- tst-dlopen-self-container tst-preload-pthread-libc +-test-srcs = tst-pathopt ++tests-internal += \ ++ circleload1 \ ++ loadtest \ ++ neededtest \ ++ neededtest2 \ ++ neededtest3 \ ++ neededtest4 \ ++ tst-create_format1 \ ++ tst-dl-hwcaps_split \ ++ tst-dlmopen2 \ ++ tst-ptrguard1 \ ++ tst-stackguard1 \ ++ tst-tls-surplus \ ++ tst-tls3 \ ++ tst-tls6 \ ++ tst-tls7 \ ++ tst-tls8 \ ++ unload \ ++ unload2 \ ++ # tests-internal ++ ++tests-container += \ ++ tst-dlopen-self-container \ ++ tst-dlopen-tlsmodid-container \ ++ tst-pldd \ ++ tst-preload-pthread-libc \ ++ # tests-container ++ ++test-srcs = \ ++ tst-pathopt \ ++ # tests-srcs ++ + selinux-enabled := $(shell cat /selinux/enforce 2> /dev/null) ++ + ifneq ($(selinux-enabled),1) +-tests-execstack-yes = tst-execstack tst-execstack-needed tst-execstack-prog ++tests-execstack-yes = \ ++ tst-execstack \ ++ tst-execstack-needed \ ++ tst-execstack-prog \ ++ # tests-execstack-yes + endif + endif + tests += $(tests-execstack-$(have-z-execstack)) + ifeq ($(run-built-tests),yes) +-tests-special += $(objpfx)tst-leaks1-mem.out \ +- $(objpfx)noload-mem.out \ +- $(objpfx)tst-ldconfig-X.out $(objpfx)tst-rtld-help.out ++tests-special += \ ++ $(objpfx)noload-mem.out \ ++ $(objpfx)tst-ldconfig-X.out \ ++ $(objpfx)tst-leaks1-mem.out \ ++ $(objpfx)tst-rtld-help.out \ ++ # tests-special + endif + tlsmod17a-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 + tlsmod18a-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 +@@ -355,9 +496,16 @@ tst-tls-many-dynamic-modules-dep = \ + tst-tls-many-dynamic-modules-dep-bad-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 + tst-tls-many-dynamic-modules-dep-bad = \ + $(foreach n,$(tst-tls-many-dynamic-modules-dep-bad-suffixes),tst-tls-manydynamic$(n)mod-dep-bad) +-extra-test-objs += $(tlsmod17a-modules:=.os) $(tlsmod18a-modules:=.os) \ +- tst-tlsalign-vars.o +-test-extras += tst-tlsmod17a tst-tlsmod18a tst-tlsalign-vars ++extra-test-objs += \ ++ $(tlsmod17a-modules:=.os) \ ++ $(tlsmod18a-modules:=.os) \ ++ tst-tlsalign-vars.o \ ++ # extra-test-objs ++test-extras += \ ++ tst-tlsalign-vars \ ++ tst-tlsmod17a \ ++ tst-tlsmod18a \ ++ # test-extras + modules-names = \ + circlemod1 \ + circlemod1a \ +@@ -609,17 +757,17 @@ modules-names-cxx = \ + tst-unique3lib \ + tst-unique3lib2 \ + tst-unique4lib \ +-# modules-names-cxx ++ # modules-names-cxx + + modules-names += \ + $(if $(CXX),$(modules-names-cxx)) \ + $(modules-execstack-$(have-z-execstack)) \ ++ $(tlsmod17a-modules) \ ++ $(tlsmod18a-modules) \ + $(tst-tls-many-dynamic-modules) \ + $(tst-tls-many-dynamic-modules-dep) \ + $(tst-tls-many-dynamic-modules-dep-bad) \ +- $(tlsmod17a-modules) \ +- $(tlsmod18a-modules) \ +-# modules-names ++ # modules-names + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. +@@ -668,35 +816,70 @@ modules-names-nobuild := filtmod1 tst-big-note-lib tst-ro-dynamic-mod + tests += $(tests-static) + + ifeq (yes,$(have-ifunc)) +-tests-ifuncstatic := ifuncmain1static ifuncmain1picstatic \ +- ifuncmain2static ifuncmain2picstatic \ +- ifuncmain4static ifuncmain4picstatic \ +- ifuncmain5static ifuncmain5picstatic \ +- ifuncmain7static ifuncmain7picstatic ++tests-ifuncstatic := \ ++ ifuncmain1static \ ++ ifuncmain1picstatic \ ++ ifuncmain2static \ ++ ifuncmain2picstatic \ ++ ifuncmain4static \ ++ ifuncmain4picstatic \ ++ ifuncmain5static \ ++ ifuncmain5picstatic \ ++ ifuncmain7static \ ++ ifuncmain7picstatic \ ++ # tests-ifuncstatic + ifeq (yes,$(have-gcc-ifunc)) + tests-ifuncstatic += ifuncmain9static ifuncmain9picstatic + endif + tests-static += $(tests-ifuncstatic) + tests-internal += $(tests-ifuncstatic) + ifeq (yes,$(build-shared)) +-tests += tst-ifunc-fault-lazy tst-ifunc-fault-bindnow ++tests += \ ++ tst-ifunc-fault-bindnow \ ++ tst-ifunc-fault-lazy \ ++ # tests + # Note: sysdeps/x86_64/ifuncmain8.c uses ifuncmain8. + tests-internal += \ +- ifuncmain1 ifuncmain1pic ifuncmain1vis ifuncmain1vispic \ +- ifuncmain1staticpic \ +- ifuncmain2 ifuncmain2pic ifuncmain3 ifuncmain4 \ +- ifuncmain5 ifuncmain5pic ifuncmain5staticpic \ +- ifuncmain7 ifuncmain7pic ++ ifuncmain1 \ ++ ifuncmain1pic \ ++ ifuncmain1staticpic \ ++ ifuncmain1vis \ ++ ifuncmain1vispic \ ++ ifuncmain2 \ ++ ifuncmain2pic \ ++ ifuncmain3 \ ++ ifuncmain4 \ ++ ifuncmain5 \ ++ ifuncmain5pic \ ++ ifuncmain5staticpic \ ++ ifuncmain7 \ ++ ifuncmain7pic \ ++ # tests-internal + ifeq (yes,$(have-gcc-ifunc)) +-tests-internal += ifuncmain9 ifuncmain9pic ++tests-internal += \ ++ ifuncmain9 \ ++ ifuncmain9pic \ ++ # tests-internal + endif +-ifunc-test-modules = ifuncdep1 ifuncdep1pic ifuncdep2 ifuncdep2pic \ +- ifuncdep5 ifuncdep5pic ++ifunc-test-modules = \ ++ ifuncdep1 \ ++ ifuncdep1pic \ ++ ifuncdep2 \ ++ ifuncdep2pic \ ++ ifuncdep5 \ ++ ifuncdep5pic \ ++ # ifunc-test-modules + extra-test-objs += $(ifunc-test-modules:=.o) + test-internal-extras += $(ifunc-test-modules) + ifeq (yes,$(have-fpie)) +-ifunc-pie-tests = ifuncmain1pie ifuncmain1vispie ifuncmain1staticpie \ +- ifuncmain5pie ifuncmain6pie ifuncmain7pie ++ifunc-pie-tests = \ ++ ifuncmain1pie \ ++ ifuncmain1staticpie \ ++ ifuncmain1vispie \ ++ ifuncmain5pie \ ++ ifuncmain6pie \ ++ ifuncmain7pie \ ++ # ifunc-pie-tests + ifeq (yes,$(have-gcc-ifunc)) + ifunc-pie-tests += ifuncmain9pie + endif +@@ -706,30 +889,50 @@ endif + tests-internal += $(ifunc-pie-tests) + tests-pie += $(ifunc-pie-tests) + endif +-modules-names += ifuncmod1 ifuncmod3 ifuncmod5 ifuncmod6 ++modules-names += \ ++ ifuncmod1 \ ++ ifuncmod3 \ ++ ifuncmod5 \ ++ ifuncmod6 \ ++ # module-names + endif + endif + + ifeq (yes,$(build-shared)) + ifeq ($(run-built-tests),yes) +-tests-special += $(objpfx)tst-pathopt.out $(objpfx)tst-rtld-load-self.out \ +- $(objpfx)tst-rtld-preload.out $(objpfx)argv0test.out \ +- $(objpfx)tst-rtld-help.out ++tests-special += \ ++ $(objpfx)argv0test.out \ ++ $(objpfx)tst-pathopt.out \ ++ $(objpfx)tst-rtld-help.out \ ++ $(objpfx)tst-rtld-load-self.out \ ++ $(objpfx)tst-rtld-preload.out \ ++ # tests-special + endif +-tests-special += $(objpfx)check-textrel.out $(objpfx)check-execstack.out \ +- $(objpfx)check-wx-segment.out \ +- $(objpfx)check-localplt.out $(objpfx)check-initfini.out ++tests-special += \ ++ $(objpfx)check-execstack.out \ ++ $(objpfx)check-initfini.out \ ++ $(objpfx)check-localplt.out \ ++ $(objpfx)check-textrel.out \ ++ $(objpfx)check-wx-segment.out \ ++ # tests-special + endif + + ifeq ($(run-built-tests),yes) +-tests-special += $(objpfx)order-cmp.out $(objpfx)tst-array1-cmp.out \ +- $(objpfx)tst-array1-static-cmp.out \ +- $(objpfx)tst-array2-cmp.out $(objpfx)tst-array3-cmp.out \ +- $(objpfx)tst-array4-cmp.out $(objpfx)tst-array5-cmp.out \ +- $(objpfx)tst-array5-static-cmp.out $(objpfx)order2-cmp.out \ +- $(objpfx)tst-initorder-cmp.out \ +- $(objpfx)tst-initorder2-cmp.out $(objpfx)tst-unused-dep.out \ +- $(objpfx)tst-unused-dep-cmp.out ++tests-special += \ ++ $(objpfx)order-cmp.out \ ++ $(objpfx)order2-cmp.out \ ++ $(objpfx)tst-array1-cmp.out \ ++ $(objpfx)tst-array1-static-cmp.out \ ++ $(objpfx)tst-array2-cmp.out \ ++ $(objpfx)tst-array3-cmp.out \ ++ $(objpfx)tst-array4-cmp.out \ ++ $(objpfx)tst-array5-cmp.out \ ++ $(objpfx)tst-array5-static-cmp.out \ ++ $(objpfx)tst-initorder-cmp.out \ ++ $(objpfx)tst-initorder2-cmp.out \ ++ $(objpfx)tst-unused-dep-cmp.out \ ++ $(objpfx)tst-unused-dep.out \ ++ # tests-special + endif + + check-abi: $(objpfx)check-abi-ld.out +@@ -811,6 +1014,7 @@ rtld-stubbed-symbols = \ + free \ + malloc \ + realloc \ ++ # rtld-stubbed-symbols + + ifeq ($(have-ssp),yes) + # rtld is not built with the stack protector, so these references will +-- +2.27.0 + diff --git a/elf-Replace-nsid-with-args.nsid-BZ-27609.patch b/elf-Replace-nsid-with-args.nsid-BZ-27609.patch new file mode 100644 index 0000000000000000000000000000000000000000..47a7031db16496fbb70476b055bc385c431b7f39 --- /dev/null +++ b/elf-Replace-nsid-with-args.nsid-BZ-27609.patch @@ -0,0 +1,50 @@ +From 1e1ecea62e899acb58c3fdf3b320a0833ddd0dff Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Thu, 30 Sep 2021 10:29:17 -0700 +Subject: [PATCH] elf: Replace nsid with args.nsid [BZ #27609] + +commit ec935dea6332cb22f9881cd1162bad156173f4b0 +Author: Florian Weimer +Date: Fri Apr 24 22:31:15 2020 +0200 + + elf: Implement __libc_early_init + +has + +@@ -856,6 +876,11 @@ no more namespaces available for dlmopen()")); + /* See if an error occurred during loading. */ + if (__glibc_unlikely (exception.errstring != NULL)) + { ++ /* Avoid keeping around a dangling reference to the libc.so link ++ map in case it has been cached in libc_map. */ ++ if (!args.libc_already_loaded) ++ GL(dl_ns)[nsid].libc_map = NULL; ++ + +do_dlopen calls _dl_open with nsid == __LM_ID_CALLER (-2), which calls +dl_open_worker with args.nsid = nsid. dl_open_worker updates args.nsid +if it is __LM_ID_CALLER. After dl_open_worker returns, it is wrong to +use nsid. + +Replace nsid with args.nsid after dl_open_worker returns. This fixes +BZ #27609. +--- + elf/dl-open.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/elf/dl-open.c b/elf/dl-open.c +index a25443f..5295e93 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -886,7 +886,7 @@ no more namespaces available for dlmopen()")); + /* Avoid keeping around a dangling reference to the libc.so link + map in case it has been cached in libc_map. */ + if (!args.libc_already_loaded) +- GL(dl_ns)[nsid].libc_map = NULL; ++ GL(dl_ns)[args.nsid].libc_map = NULL; + + /* Remove the object from memory. It may be in an inconsistent + state if relocation failed, for example. */ +-- +1.8.3.1 + diff --git a/elf-Sort-tests-and-modules-names.patch b/elf-Sort-tests-and-modules-names.patch new file mode 100644 index 0000000000000000000000000000000000000000..49bab1d15a4b18abdb5ca6f137fbd13ce2619b84 --- /dev/null +++ b/elf-Sort-tests-and-modules-names.patch @@ -0,0 +1,546 @@ +From 31186e2cb74b2403726060276512c39cc89a1478 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Mon, 13 Dec 2021 09:43:52 -0800 +Subject: [PATCH] elf: Sort tests and modules-names + +Sort tests and modules-names to reduce future conflicts. + +(cherry picked from commit 28713c06129f8f64f88c423266e6ff2880216509) +--- + elf/Makefile | 512 ++++++++++++++++++++++++++++++++++++++------------- + 1 file changed, 385 insertions(+), 127 deletions(-) + +diff --git a/elf/Makefile b/elf/Makefile +index 118d579c42..ec1cd49bb3 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -193,39 +193,133 @@ static-dlopen-environment = \ + tst-tls9-static-ENV = $(static-dlopen-environment) + tst-single_threaded-static-dlopen-ENV = $(static-dlopen-environment) + +-tests += restest1 preloadtest loadfail multiload origtest resolvfail \ +- constload1 order noload filter \ +- reldep reldep2 reldep3 reldep4 nodelete nodelete2 \ +- nodlopen nodlopen2 lateglobal initfirst global \ +- restest2 next dblload dblunload reldep5 reldep6 reldep7 reldep8 \ +- tst-tls4 tst-tls5 \ +- tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-tls15 \ +- tst-tls16 tst-tls17 tst-tls18 tst-tls19 tst-tls-dlinfo \ +- tst-align tst-align2 \ +- tst-dlmodcount tst-dlopenrpath tst-deep1 \ +- tst-dlmopen1 tst-dlmopen3 \ +- unload3 unload4 unload5 unload6 unload7 unload8 tst-global1 order2 \ +- tst-audit1 tst-audit2 tst-audit8 tst-audit9 \ +- tst-addr1 tst-thrlock \ +- tst-unique1 tst-unique2 $(if $(CXX),tst-unique3 tst-unique4 \ +- tst-nodelete tst-dlopen-nodelete-reloc) \ +- tst-initorder tst-initorder2 tst-relsort1 tst-null-argv \ +- tst-tlsalign tst-tlsalign-extern tst-nodelete-opened \ +- tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \ +- tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \ +- tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note \ +- tst-unwind-ctor tst-unwind-main tst-audit13 \ +- tst-sonamemove-link tst-sonamemove-dlopen tst-dlopen-tlsmodid \ +- tst-dlopen-self tst-auditmany tst-initfinilazyfail tst-dlopenfail \ +- tst-dlopenfail-2 \ +- tst-filterobj tst-filterobj-dlopen tst-auxobj tst-auxobj-dlopen \ +- tst-audit14 tst-audit15 tst-audit16 tst-audit17 \ +- tst-single_threaded tst-single_threaded-pthread \ +- tst-tls-ie tst-tls-ie-dlmopen argv0test \ +- tst-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask \ +- tst-tls20 tst-tls21 tst-dlmopen-dlerror tst-dlmopen-gethostbyname \ +- tst-dl-is_dso tst-ro-dynamic ++tests += \ ++ argv0test \ ++ constload1 \ ++ dblload \ ++ dblunload \ ++ filter \ ++ global \ ++ initfirst \ ++ lateglobal \ ++ loadfail \ ++ multiload \ ++ next \ ++ nodelete \ ++ nodelete2 \ ++ nodlopen \ ++ nodlopen2 \ ++ noload \ ++ order \ ++ order2 \ ++ origtest \ ++ preloadtest \ ++ reldep \ ++ reldep2 \ ++ reldep3 \ ++ reldep4 \ ++ reldep5 \ ++ reldep6 \ ++ reldep7 \ ++ reldep8 \ ++ resolvfail \ ++ restest1 \ ++ restest2 \ ++ tst-absolute-sym \ ++ tst-absolute-zero \ ++ tst-addr1 \ ++ tst-align \ ++ tst-align2 \ ++ tst-audit1 \ ++ tst-audit2 \ ++ tst-audit8 \ ++ tst-audit9 \ ++ tst-audit11 \ ++ tst-audit12 \ ++ tst-audit13 \ ++ tst-audit14 \ ++ tst-audit15 \ ++ tst-audit16 \ ++ tst-audit17 \ ++ tst-auditmany \ ++ tst-auxobj \ ++ tst-auxobj-dlopen \ ++ tst-big-note \ ++ tst-debug1 \ ++ tst-deep1 \ ++ tst-dl-is_dso \ ++ tst-dlmodcount \ ++ tst-dlmopen1 \ ++ tst-dlmopen3 \ ++ tst-dlmopen-dlerror \ ++ tst-dlmopen-gethostbyname \ ++ tst-dlopenfail \ ++ tst-dlopenfail-2 \ ++ tst-dlopenrpath \ ++ tst-dlopen-self \ ++ tst-dlopen-tlsmodid \ ++ tst-dlsym-error \ ++ tst-filterobj \ ++ tst-filterobj-dlopen \ ++ tst-glibc-hwcaps \ ++ tst-glibc-hwcaps-mask \ ++ tst-glibc-hwcaps-prepend \ ++ tst-global1 \ ++ tst-initfinilazyfail \ ++ tst-initorder \ ++ tst-initorder2 \ ++ tst-latepthread \ ++ tst-main1 \ ++ tst-nodelete2 \ ++ tst-nodelete-dlclose \ ++ tst-nodelete-opened \ ++ tst-noload \ ++ tst-null-argv \ ++ tst-relsort1 \ ++ tst-ro-dynamic \ ++ tst-single_threaded \ ++ tst-single_threaded-pthread \ ++ tst-sonamemove-dlopen \ ++ tst-sonamemove-link \ ++ tst-thrlock \ ++ tst-tls10 \ ++ tst-tls11 \ ++ tst-tls12 \ ++ tst-tls13 \ ++ tst-tls14 \ ++ tst-tls15 \ ++ tst-tls16 \ ++ tst-tls17 \ ++ tst-tls18 \ ++ tst-tls19 \ ++ tst-tls20 \ ++ tst-tls21 \ ++ tst-tls4 \ ++ tst-tls5 \ ++ tst-tlsalign \ ++ tst-tlsalign-extern \ ++ tst-tls-dlinfo \ ++ tst-tls-ie \ ++ tst-tls-ie-dlmopen \ ++ tst-tls-manydynamic \ ++ tst-unique1 \ ++ tst-unique2 \ ++ tst-unwind-ctor \ ++ tst-unwind-main \ ++ unload3 \ ++ unload4 \ ++ unload5 \ ++ unload6 \ ++ unload7 \ ++ unload8 \ + # reldep9 ++tests-cxx = \ ++ tst-dlopen-nodelete-reloc \ ++ tst-nodelete \ ++ tst-unique3 \ ++ tst-unique4 \ ++ ++tests += $(if $(CXX),$(tests-cxx)) + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ + tst-tls3 tst-tls6 tst-tls7 tst-tls8 tst-dlmopen2 \ +@@ -263,101 +357,265 @@ tst-tls-many-dynamic-modules-dep-bad = \ + extra-test-objs += $(tlsmod17a-modules:=.os) $(tlsmod18a-modules:=.os) \ + tst-tlsalign-vars.o + test-extras += tst-tlsmod17a tst-tlsmod18a tst-tlsalign-vars +-modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ +- testobj1_1 failobj constload2 constload3 unloadmod \ +- dep1 dep2 dep3 dep4 vismod1 vismod2 vismod3 \ +- nodelmod1 nodelmod2 nodelmod3 nodelmod4 \ +- nodel2mod1 nodel2mod2 nodel2mod3 \ +- nodlopenmod nodlopenmod2 filtmod1 filtmod2 \ +- reldepmod1 reldepmod2 reldepmod3 reldepmod4 nextmod1 nextmod2 \ +- reldep4mod1 reldep4mod2 reldep4mod3 reldep4mod4 \ +- neededobj1 neededobj2 neededobj3 neededobj4 \ +- neededobj5 neededobj6 firstobj globalmod1 \ +- unload2mod unload2dep ltglobmod1 ltglobmod2 pathoptobj \ +- dblloadmod1 dblloadmod2 dblloadmod3 reldepmod5 reldepmod6 \ +- reldep6mod0 reldep6mod1 reldep6mod2 reldep6mod3 reldep6mod4 \ +- reldep7mod1 reldep7mod2 \ +- tst-tlsmod1 tst-tlsmod2 tst-tlsmod3 tst-tlsmod4 \ +- tst-tlsmod5 tst-tlsmod6 tst-tlsmod7 tst-tlsmod8 \ +- tst-tlsmod9 tst-tlsmod10 tst-tlsmod11 tst-tlsmod12 \ +- tst-tlsmod13 tst-tlsmod13a tst-tlsmod14a tst-tlsmod14b \ +- tst-tlsmod15a tst-tlsmod15b tst-tlsmod16a tst-tlsmod16b \ +- $(tlsmod17a-modules) tst-tlsmod17b $(tlsmod18a-modules) \ +- tst-tls19mod1 tst-tls19mod2 tst-tls19mod3 \ +- circlemod1 circlemod1a circlemod2 circlemod2a \ +- circlemod3 circlemod3a \ +- reldep8mod1 reldep8mod2 reldep8mod3 \ +- reldep9mod1 reldep9mod2 reldep9mod3 \ +- tst-alignmod tst-alignmod2 \ +- $(modules-execstack-$(have-z-execstack)) \ +- tst-dlopenrpathmod tst-deep1mod1 tst-deep1mod2 tst-deep1mod3 \ +- tst-dlmopen1mod tst-auditmod1 \ +- unload3mod1 unload3mod2 unload3mod3 unload3mod4 \ +- unload4mod1 unload4mod2 unload4mod3 unload4mod4 \ +- unload6mod1 unload6mod2 unload6mod3 \ +- unload7mod1 unload7mod2 \ +- unload8mod1 unload8mod1x unload8mod2 unload8mod3 \ +- order2mod1 order2mod2 order2mod3 order2mod4 \ +- tst-unique1mod1 tst-unique1mod2 \ +- tst-unique2mod1 tst-unique2mod2 \ +- tst-auditmod9a tst-auditmod9b \ +- $(if $(CXX),tst-unique3lib tst-unique3lib2 tst-unique4lib \ +- tst-nodelete-uniquemod tst-nodelete-rtldmod \ +- tst-nodelete-zmod \ +- tst-dlopen-nodelete-reloc-mod1 \ +- tst-dlopen-nodelete-reloc-mod2 \ +- tst-dlopen-nodelete-reloc-mod3 \ +- tst-dlopen-nodelete-reloc-mod4 \ +- tst-dlopen-nodelete-reloc-mod5 \ +- tst-dlopen-nodelete-reloc-mod6 \ +- tst-dlopen-nodelete-reloc-mod7 \ +- tst-dlopen-nodelete-reloc-mod8 \ +- tst-dlopen-nodelete-reloc-mod9 \ +- tst-dlopen-nodelete-reloc-mod10 \ +- tst-dlopen-nodelete-reloc-mod11 \ +- tst-dlopen-nodelete-reloc-mod12 \ +- tst-dlopen-nodelete-reloc-mod13 \ +- tst-dlopen-nodelete-reloc-mod14 \ +- tst-dlopen-nodelete-reloc-mod15 \ +- tst-dlopen-nodelete-reloc-mod16 \ +- tst-dlopen-nodelete-reloc-mod17) \ +- tst-initordera1 tst-initorderb1 \ +- tst-initordera2 tst-initorderb2 \ +- tst-initordera3 tst-initordera4 \ +- tst-initorder2a tst-initorder2b tst-initorder2c \ +- tst-initorder2d \ +- tst-relsort1mod1 tst-relsort1mod2 tst-array2dep \ +- tst-array5dep tst-null-argv-lib \ +- tst-tlsalign-lib tst-nodelete-opened-lib tst-nodelete2mod \ +- tst-audit11mod1 tst-audit11mod2 tst-auditmod11 \ +- tst-audit12mod1 tst-audit12mod2 tst-audit12mod3 tst-auditmod12 \ +- tst-latepthreadmod $(tst-tls-many-dynamic-modules) \ +- $(tst-tls-many-dynamic-modules-dep) \ +- $(tst-tls-many-dynamic-modules-dep-bad) \ +- tst-nodelete-dlclose-dso tst-nodelete-dlclose-plugin \ +- tst-main1mod tst-absolute-sym-lib \ +- tst-absolute-zero-lib tst-big-note-lib tst-unwind-ctor-lib \ +- tst-audit13mod1 tst-sonamemove-linkmod1 \ +- tst-sonamemove-runmod1 tst-sonamemove-runmod2 \ +- tst-auditmanymod1 tst-auditmanymod2 tst-auditmanymod3 \ +- tst-auditmanymod4 tst-auditmanymod5 tst-auditmanymod6 \ +- tst-auditmanymod7 tst-auditmanymod8 tst-auditmanymod9 \ +- tst-initlazyfailmod tst-finilazyfailmod \ +- tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2 \ +- tst-dlopenfailmod3 tst-dlopenfailnodelmod tst-ldconfig-ld-mod \ +- tst-filterobj-flt tst-filterobj-aux tst-filterobj-filtee \ +- tst-auditlogmod-1 tst-auditlogmod-2 tst-auditlogmod-3 \ +- tst-single_threaded-mod1 tst-single_threaded-mod2 \ +- tst-single_threaded-mod3 tst-single_threaded-mod4 \ +- tst-tls-ie-mod0 tst-tls-ie-mod1 tst-tls-ie-mod2 \ +- tst-tls-ie-mod3 tst-tls-ie-mod4 tst-tls-ie-mod5 \ +- tst-tls-ie-mod6 libmarkermod1-1 libmarkermod1-2 libmarkermod1-3 \ +- libmarkermod2-1 libmarkermod2-2 \ +- libmarkermod3-1 libmarkermod3-2 libmarkermod3-3 \ +- libmarkermod4-1 libmarkermod4-2 libmarkermod4-3 libmarkermod4-4 \ +- tst-tls20mod-bad tst-tls21mod tst-dlmopen-dlerror-mod \ +- tst-auxvalmod \ +- tst-dlmopen-gethostbyname-mod tst-ro-dynamic-mod \ ++modules-names = \ ++ circlemod1 \ ++ circlemod1a \ ++ circlemod2 \ ++ circlemod2a \ ++ circlemod3 \ ++ circlemod3a \ ++ constload2 \ ++ constload3 \ ++ dblloadmod1 \ ++ dblloadmod2 \ ++ dblloadmod3 \ ++ dep1 \ ++ dep2 \ ++ dep3 \ ++ dep4 \ ++ failobj \ ++ filtmod1 \ ++ filtmod2 \ ++ firstobj \ ++ globalmod1 \ ++ libmarkermod1-1 \ ++ libmarkermod1-2 \ ++ libmarkermod1-3 \ ++ libmarkermod2-1 \ ++ libmarkermod2-2 \ ++ libmarkermod3-1 \ ++ libmarkermod3-2 \ ++ libmarkermod3-3 \ ++ libmarkermod4-1 \ ++ libmarkermod4-2 \ ++ libmarkermod4-3 \ ++ libmarkermod4-4 \ ++ ltglobmod1 \ ++ ltglobmod2 \ ++ neededobj1 \ ++ neededobj2 \ ++ neededobj3 \ ++ neededobj4 \ ++ neededobj5 \ ++ neededobj6 \ ++ nextmod1 \ ++ nextmod2 \ ++ nodel2mod1 \ ++ nodel2mod2 \ ++ nodel2mod3 \ ++ nodelmod1 \ ++ nodelmod2 \ ++ nodelmod3 \ ++ nodelmod4 \ ++ nodlopenmod \ ++ nodlopenmod2 \ ++ order2mod1 \ ++ order2mod2 \ ++ order2mod3 \ ++ order2mod4 \ ++ pathoptobj \ ++ reldep4mod1 \ ++ reldep4mod2 \ ++ reldep4mod3 \ ++ reldep4mod4 \ ++ reldep6mod0 \ ++ reldep6mod1 \ ++ reldep6mod2 \ ++ reldep6mod3 \ ++ reldep6mod4 \ ++ reldep7mod1 \ ++ reldep7mod2 \ ++ reldep8mod1 \ ++ reldep8mod2 \ ++ reldep8mod3 \ ++ reldep9mod1 \ ++ reldep9mod2 \ ++ reldep9mod3 \ ++ reldepmod1 \ ++ reldepmod2 \ ++ reldepmod3 \ ++ reldepmod4 \ ++ reldepmod5 \ ++ reldepmod6 \ ++ testobj1 \ ++ testobj1_1 \ ++ testobj2 \ ++ testobj3 \ ++ testobj4 \ ++ testobj5 \ ++ testobj6 \ ++ tst-absolute-sym-lib \ ++ tst-absolute-zero-lib \ ++ tst-alignmod \ ++ tst-alignmod2 \ ++ tst-array2dep \ ++ tst-array5dep \ ++ tst-audit11mod1 \ ++ tst-audit11mod2 \ ++ tst-audit12mod1 \ ++ tst-audit12mod2 \ ++ tst-audit12mod3 \ ++ tst-audit13mod1 \ ++ tst-auditlogmod-1 \ ++ tst-auditlogmod-2 \ ++ tst-auditlogmod-3 \ ++ tst-auditmanymod1 \ ++ tst-auditmanymod2 \ ++ tst-auditmanymod3 \ ++ tst-auditmanymod4 \ ++ tst-auditmanymod5 \ ++ tst-auditmanymod6 \ ++ tst-auditmanymod7 \ ++ tst-auditmanymod8 \ ++ tst-auditmanymod9 \ ++ tst-auditmod1 \ ++ tst-auditmod9a \ ++ tst-auditmod9b \ ++ tst-auditmod11 \ ++ tst-auditmod12 \ ++ tst-auxvalmod \ ++ tst-big-note-lib \ ++ tst-deep1mod1 \ ++ tst-deep1mod2 \ ++ tst-deep1mod3 \ ++ tst-dlmopen1mod \ ++ tst-dlmopen-dlerror-mod \ ++ tst-dlmopen-gethostbyname-mod \ ++ tst-dlopenfaillinkmod \ ++ tst-dlopenfailmod1 \ ++ tst-dlopenfailmod2 \ ++ tst-dlopenfailmod3 \ ++ tst-dlopenfailnodelmod \ ++ tst-dlopenrpathmod \ ++ tst-filterobj-aux \ ++ tst-filterobj-filtee \ ++ tst-filterobj-flt \ ++ tst-finilazyfailmod \ ++ tst-initlazyfailmod \ ++ tst-initorder2a \ ++ tst-initorder2b \ ++ tst-initorder2c \ ++ tst-initorder2d \ ++ tst-initordera1 \ ++ tst-initordera2 \ ++ tst-initordera3 \ ++ tst-initordera4 \ ++ tst-initorderb1 \ ++ tst-initorderb2 \ ++ tst-latepthreadmod \ ++ tst-ldconfig-ld-mod \ ++ tst-main1mod \ ++ tst-nodelete2mod \ ++ tst-nodelete-dlclose-dso \ ++ tst-nodelete-dlclose-plugin \ ++ tst-nodelete-opened-lib \ ++ tst-null-argv-lib \ ++ tst-relsort1mod1 \ ++ tst-relsort1mod2 \ ++ tst-ro-dynamic-mod \ ++ tst-single_threaded-mod1 \ ++ tst-single_threaded-mod2 \ ++ tst-single_threaded-mod3 \ ++ tst-single_threaded-mod4 \ ++ tst-sonamemove-linkmod1 \ ++ tst-sonamemove-runmod1 \ ++ tst-sonamemove-runmod2 \ ++ tst-tls19mod1 \ ++ tst-tls19mod2 \ ++ tst-tls19mod3 \ ++ tst-tls20mod-bad \ ++ tst-tls21mod \ ++ tst-tlsalign-lib \ ++ tst-tls-ie-mod0 \ ++ tst-tls-ie-mod1 \ ++ tst-tls-ie-mod2 \ ++ tst-tls-ie-mod3 \ ++ tst-tls-ie-mod4 \ ++ tst-tls-ie-mod5 \ ++ tst-tls-ie-mod6 \ ++ tst-tlsmod1 \ ++ tst-tlsmod10 \ ++ tst-tlsmod11 \ ++ tst-tlsmod12 \ ++ tst-tlsmod13 \ ++ tst-tlsmod13a \ ++ tst-tlsmod14a \ ++ tst-tlsmod14b \ ++ tst-tlsmod15a \ ++ tst-tlsmod15b \ ++ tst-tlsmod16a \ ++ tst-tlsmod16b \ ++ tst-tlsmod17b \ ++ tst-tlsmod2 \ ++ tst-tlsmod3 \ ++ tst-tlsmod4 \ ++ tst-tlsmod5 \ ++ tst-tlsmod6 \ ++ tst-tlsmod7 \ ++ tst-tlsmod8 \ ++ tst-tlsmod9 \ ++ tst-unique1mod1 \ ++ tst-unique1mod2 \ ++ tst-unique2mod1 \ ++ tst-unique2mod2 \ ++ tst-unwind-ctor-lib \ ++ unload2dep \ ++ unload2mod \ ++ unload3mod1 \ ++ unload3mod2 \ ++ unload3mod3 \ ++ unload3mod4 \ ++ unload4mod1 \ ++ unload4mod2 \ ++ unload4mod3 \ ++ unload4mod4 \ ++ unload6mod1 \ ++ unload6mod2 \ ++ unload6mod3 \ ++ unload7mod1 \ ++ unload7mod2 \ ++ unload8mod1 \ ++ unload8mod1x \ ++ unload8mod2 \ ++ unload8mod3 \ ++ unloadmod \ ++ vismod1 \ ++ vismod2 \ ++ vismod3 \ ++ ++modules-names-cxx = \ ++ tst-dlopen-nodelete-reloc-mod1 \ ++ tst-dlopen-nodelete-reloc-mod10 \ ++ tst-dlopen-nodelete-reloc-mod11 \ ++ tst-dlopen-nodelete-reloc-mod12 \ ++ tst-dlopen-nodelete-reloc-mod13 \ ++ tst-dlopen-nodelete-reloc-mod14 \ ++ tst-dlopen-nodelete-reloc-mod15 \ ++ tst-dlopen-nodelete-reloc-mod16 \ ++ tst-dlopen-nodelete-reloc-mod17 \ ++ tst-dlopen-nodelete-reloc-mod2 \ ++ tst-dlopen-nodelete-reloc-mod3 \ ++ tst-dlopen-nodelete-reloc-mod4 \ ++ tst-dlopen-nodelete-reloc-mod5 \ ++ tst-dlopen-nodelete-reloc-mod6 \ ++ tst-dlopen-nodelete-reloc-mod7 \ ++ tst-dlopen-nodelete-reloc-mod8 \ ++ tst-dlopen-nodelete-reloc-mod9 \ ++ tst-nodelete-rtldmod \ ++ tst-nodelete-uniquemod \ ++ tst-nodelete-zmod \ ++ tst-unique3lib \ ++ tst-unique3lib2 \ ++ tst-unique4lib \ ++ ++modules-names += \ ++ $(if $(CXX),$(modules-names-cxx)) \ ++ $(modules-execstack-$(have-z-execstack)) \ ++ $(tst-tls-many-dynamic-modules) \ ++ $(tst-tls-many-dynamic-modules-dep) \ ++ $(tst-tls-many-dynamic-modules-dep-bad) \ ++ $(tlsmod17a-modules) \ ++ $(tlsmod18a-modules) \ + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. +-- +2.27.0 + diff --git a/elf-Unconditionally-use-__ehdr_start.patch b/elf-Unconditionally-use-__ehdr_start.patch new file mode 100644 index 0000000000000000000000000000000000000000..b30438db5358b87abf931dd3cdb9e939bd65808b --- /dev/null +++ b/elf-Unconditionally-use-__ehdr_start.patch @@ -0,0 +1,177 @@ +From 302247c89121e8d4c7629e589edbb4974fff6edb Mon Sep 17 00:00:00 2001 +From: Fangrui Song +Date: Tue, 10 Aug 2021 11:04:56 -0700 +Subject: [PATCH] elf: Unconditionally use __ehdr_start + +We can consider __ehdr_start (from binutils 2.23 onwards) +unconditionally supported, since configure.ac requires binutils>=2.25. + +The configure.ac check is related to an ia64 bug fixed by binutils 2.24. +See https://sourceware.org/pipermail/libc-alpha/2014-August/053503.html + +Tested on x86_64-linux-gnu. Tested build-many-glibcs.py with +aarch64-linux-gnu and s390x-linux-gnu. + +Reviewed-by: Szabolcs Nagy +--- + config.h.in | 3 --- + configure | 52 ---------------------------------------------------- + configure.ac | 34 ---------------------------------- + elf/rtld.c | 13 ++++--------- + 4 files changed, 4 insertions(+), 98 deletions(-) + +diff --git a/config.h.in b/config.h.in +index 8b45a3a..0d92504 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -198,9 +198,6 @@ + /* Define if CC supports attribute retain. */ + #undef HAVE_GNU_RETAIN + +-/* Define if the linker defines __ehdr_start. */ +-#undef HAVE_EHDR_START +- + /* Define to 1 if the assembler needs intermediate aliases to define + multiple symbol versions for one symbol. */ + #define SYMVER_NEEDS_ALIAS 0 +diff --git a/configure b/configure +index 9619c10..7272fbf 100755 +--- a/configure ++++ b/configure +@@ -6636,58 +6636,6 @@ if test $libc_cv_predef_fortify_source = yes; then + fi + + +-# Some linkers on some architectures support __ehdr_start but with +-# bugs. Make sure usage of it does not create relocations in the +-# output (as the linker should resolve them all for us). +-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the linker provides working __ehdr_start" >&5 +-$as_echo_n "checking whether the linker provides working __ehdr_start... " >&6; } +-if ${libc_cv_ehdr_start+:} false; then : +- $as_echo_n "(cached) " >&6 +-else +- +-old_CFLAGS="$CFLAGS" +-old_LDFLAGS="$LDFLAGS" +-old_LIBS="$LIBS" +-CFLAGS="$CFLAGS -fPIC" +-LDFLAGS="$LDFLAGS -nostdlib -nostartfiles -shared $no_ssp" +-LIBS= +-cat confdefs.h - <<_ACEOF >conftest.$ac_ext +-/* end confdefs.h. */ +- +-typedef struct { +- char foo; +- long val; +-} Ehdr; +-extern const Ehdr __ehdr_start __attribute__ ((visibility ("hidden"))); +-long ehdr (void) { return __ehdr_start.val; } +- +-_ACEOF +-if ac_fn_c_try_link "$LINENO"; then : +- if $READELF -r conftest | grep -F __ehdr_start >/dev/null; then +- libc_cv_ehdr_start=broken +- else +- libc_cv_ehdr_start=yes +- fi +-else +- libc_cv_ehdr_start=no +-fi +-rm -f core conftest.err conftest.$ac_objext \ +- conftest$ac_exeext conftest.$ac_ext +-CFLAGS="$old_CFLAGS" +-LDFLAGS="$old_LDFLAGS" +-LIBS="$old_LIBS" +- +-fi +-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_ehdr_start" >&5 +-$as_echo "$libc_cv_ehdr_start" >&6; } +-if test "$libc_cv_ehdr_start" = yes; then +- $as_echo "#define HAVE_EHDR_START 1" >>confdefs.h +- +-elif test "$libc_cv_ehdr_start" = broken; then +- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: linker is broken -- you should upgrade" >&5 +-$as_echo "$as_me: WARNING: linker is broken -- you should upgrade" >&2;} +-fi +- + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the assembler requires one version per symbol" >&5 + $as_echo_n "checking whether the assembler requires one version per symbol... " >&6; } + if ${libc_cv_symver_needs_alias+:} false; then : +diff --git a/configure.ac b/configure.ac +index 34ecbba..af47cd5 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1662,40 +1662,6 @@ if test $libc_cv_predef_fortify_source = yes; then + fi + AC_SUBST(CPPUNDEFS) + +-# Some linkers on some architectures support __ehdr_start but with +-# bugs. Make sure usage of it does not create relocations in the +-# output (as the linker should resolve them all for us). +-AC_CACHE_CHECK([whether the linker provides working __ehdr_start], +- libc_cv_ehdr_start, [ +-old_CFLAGS="$CFLAGS" +-old_LDFLAGS="$LDFLAGS" +-old_LIBS="$LIBS" +-CFLAGS="$CFLAGS -fPIC" +-LDFLAGS="$LDFLAGS -nostdlib -nostartfiles -shared $no_ssp" +-LIBS= +-AC_LINK_IFELSE([AC_LANG_SOURCE([ +-typedef struct { +- char foo; +- long val; +-} Ehdr; +-extern const Ehdr __ehdr_start __attribute__ ((visibility ("hidden"))); +-long ehdr (void) { return __ehdr_start.val; } +-])], +- [if $READELF -r conftest | grep -F __ehdr_start >/dev/null; then +- libc_cv_ehdr_start=broken +- else +- libc_cv_ehdr_start=yes +- fi], [libc_cv_ehdr_start=no]) +-CFLAGS="$old_CFLAGS" +-LDFLAGS="$old_LDFLAGS" +-LIBS="$old_LIBS" +-]) +-if test "$libc_cv_ehdr_start" = yes; then +- AC_DEFINE([HAVE_EHDR_START]) +-elif test "$libc_cv_ehdr_start" = broken; then +- AC_MSG_WARN([linker is broken -- you should upgrade]) +-fi +- + dnl Starting with binutils 2.35, GAS can attach multiple symbol versions + dnl to one symbol (PR 23840). + AC_CACHE_CHECK(whether the assembler requires one version per symbol, +diff --git a/elf/rtld.c b/elf/rtld.c +index d733359..878e648 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -1684,21 +1684,16 @@ dl_main (const ElfW(Phdr) *phdr, + if (GLRO(dl_use_load_bias) == (ElfW(Addr)) -2) + GLRO(dl_use_load_bias) = main_map->l_addr == 0 ? -1 : 0; + +- /* Set up the program header information for the dynamic linker +- itself. It is needed in the dl_iterate_phdr callbacks. */ +- const ElfW(Ehdr) *rtld_ehdr; +- + /* Starting from binutils-2.23, the linker will define the magic symbol + __ehdr_start to point to our own ELF header if it is visible in a + segment that also includes the phdrs. If that's not available, we use + the old method that assumes the beginning of the file is part of the + lowest-addressed PT_LOAD segment. */ +-#ifdef HAVE_EHDR_START + extern const ElfW(Ehdr) __ehdr_start __attribute__ ((visibility ("hidden"))); +- rtld_ehdr = &__ehdr_start; +-#else +- rtld_ehdr = (void *) GL(dl_rtld_map).l_map_start; +-#endif ++ ++ /* Set up the program header information for the dynamic linker ++ itself. It is needed in the dl_iterate_phdr callbacks. */ ++ const ElfW(Ehdr) *rtld_ehdr = &__ehdr_start; + assert (rtld_ehdr->e_ehsize == sizeof *rtld_ehdr); + assert (rtld_ehdr->e_phentsize == sizeof (ElfW(Phdr))); + +-- +1.8.3.1 + diff --git a/fix-CVE-2019-1010023.patch b/fix-CVE-2019-1010023.patch new file mode 100644 index 0000000000000000000000000000000000000000..efa322e8fae961626d8e62c7a553b5f1f64f272b --- /dev/null +++ b/fix-CVE-2019-1010023.patch @@ -0,0 +1,66 @@ +From fe1ffef2eec9c6634a1e9af951eb68f0f5614470 Mon Sep 17 00:00:00 2001 +From: xujing +Date: Thu, 2 Dec 2021 11:41:46 +0800 +Subject: [PATCH] glibc: fix CVE-2019-1010023 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +| PT_LOAD +| +| […] Loadable segment entries in the program header table appear in +| ascending order, sorted on the p_vaddr member. + +http://www.sco.com/developers/gabi/latest/ch5.pheader.html + +Some check needed to fix vulnerability in load commands mapping reported by + +https://sourceware.org/bugzilla/show_bug.cgi?id=22851 + +Signed-off-by: lvying +Signed-off-by: xujing +--- + elf/dl-map-segments.h | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/elf/dl-map-segments.h b/elf/dl-map-segments.h +index 084076a2..a41ae73b 100644 +--- a/elf/dl-map-segments.h ++++ b/elf/dl-map-segments.h +@@ -33,6 +33,7 @@ _dl_map_segments (struct link_map *l, int fd, + struct link_map *loader) + { + const struct loadcmd *c = loadcmds; ++ ElfW(Addr) l_map_end_aligned; + + if (__glibc_likely (type == ET_DYN)) + { +@@ -61,6 +62,8 @@ _dl_map_segments (struct link_map *l, int fd, + return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT; + + l->l_map_end = l->l_map_start + maplength; ++ l_map_end_aligned = ((l->l_map_end + GLRO(dl_pagesize) - 1) ++ & ~(GLRO(dl_pagesize) - 1)); + l->l_addr = l->l_map_start - c->mapstart; + + if (has_holes) +@@ -85,10 +88,16 @@ _dl_map_segments (struct link_map *l, int fd, + /* Remember which part of the address space this object uses. */ + l->l_map_start = c->mapstart + l->l_addr; + l->l_map_end = l->l_map_start + maplength; ++ l_map_end_aligned = ((l->l_map_end + GLRO(dl_pagesize) - 1) ++ & ~(GLRO(dl_pagesize) - 1)); + l->l_contiguous = !has_holes; + + while (c < &loadcmds[nloadcmds]) + { ++ if ((l->l_addr + c->mapend) > l_map_end_aligned || ++ (l->l_addr + c->mapstart) < l->l_map_start) ++ return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT; ++ + if (c->mapend > c->mapstart + /* Map the segment contents from the file. */ + && (__mmap ((void *) (l->l_addr + c->mapstart), +-- +2.23.0 + diff --git a/fix-tst-glibcsyscalls-due-to-kernel-reserved-some-sy.patch b/fix-tst-glibcsyscalls-due-to-kernel-reserved-some-sy.patch new file mode 100644 index 0000000000000000000000000000000000000000..2a635da5f57b796de909a65c5a388d787a2c7996 --- /dev/null +++ b/fix-tst-glibcsyscalls-due-to-kernel-reserved-some-sy.patch @@ -0,0 +1,55 @@ +From 34d9611a38eceba7adf7270d0318629b4a325f56 Mon Sep 17 00:00:00 2001 +From: Qingqing Li +Date: Mon, 7 Feb 2022 20:37:25 +0800 +Subject: [PATCH] fix tst-glibcsyscalls due to kernel reserved some syscalls +kernel has resolved kabi_reserved441 ~ kabi_reserved456, and this will cause +misc/tst-glibcsyscalls failed, errors are like below: + +[ 1241s] =====FAIL: misc/tst-glibcsyscalls.out===== +[ 1241s] info: glibc syscall 'mount_setattr' not known to kernel +[ 1241s] info: glibc syscall 'epoll_pwait2' not known to kernel +[ 1241s] info: glibc syscall 'landlock_add_rule' not known to kernel +[ 1241s] info: glibc syscall 'landlock_restrict_self' not known to kernel +[ 1241s] info: glibc syscall 'landlock_create_ruleset' not known to kernel +[ 1241s] error: kernel syscall 'kabi_reserved454' (454) not known to glibc +[ 1241s] error: kernel syscall 'kabi_reserved442' (442) not known to glibc +[ 1241s] error: kernel syscall 'kabi_reserved448' (448) not known to glibc +[ 1241s] error: kernel syscall 'kabi_reserved447' (447) not known to glibc +[ 1241s] error: kernel syscall 'kabi_reserved450' (450) not known to glibc +[ 1241s] error: kernel syscall 'kabi_reserved456' (456) not known to glibc +[ 1241s] error: kernel syscall 'kabi_reserved441' (441) not known to glibc +[ 1241s] error: kernel syscall 'kabi_reserved443' (443) not known to glibc +[ 1241s] error: kernel syscall 'kabi_reserved449' (449) not known to glibc +[ 1241s] error: kernel syscall 'kabi_reserved455' (455) not known to glibc +[ 1241s] error: kernel syscall 'kabi_reserved444' (444) not known to glibc +[ 1241s] error: kernel syscall 'kabi_reserved452' (452) not known to glibc +[ 1241s] error: kernel syscall 'kabi_reserved453' (453) not known to glibc +[ 1241s] error: kernel syscall 'kabi_reserved445' (445) not known to glibc +[ 1241s] error: kernel syscall 'kabi_reserved451' (451) not known to glibc +[ 1241s] error: kernel syscall 'kabi_reserved446' (446) not known to glibc + +--- + sysdeps/unix/sysv/linux/tst-glibcsyscalls.py | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/sysdeps/unix/sysv/linux/tst-glibcsyscalls.py b/sysdeps/unix/sysv/linux/tst-glibcsyscalls.py +index 4a00bbab..d2d74c9c 100644 +--- a/sysdeps/unix/sysv/linux/tst-glibcsyscalls.py ++++ b/sysdeps/unix/sysv/linux/tst-glibcsyscalls.py +@@ -67,9 +67,10 @@ def main(): + # superset of the kernel system call set. + if glibc_names.kernel_version >= kernel_version: + for name in kernel_constants.keys() - glibc_constants.keys(): +- print("error: kernel syscall {!r} ({}) not known to glibc" +- .format(name, kernel_constants[name])) +- errors = 1 ++ if 'kabi_reserved' not in name: ++ print("error: kernel syscall {!r} ({}) not known to glibc" ++ .format(name, kernel_constants[name])) ++ errors = 1 + else: + for name in kernel_constants.keys() - glibc_constants.keys(): + print("warning: kernel syscall {!r} ({}) not known to glibc" +-- +2.27.0 + diff --git a/gaiconf_init-Avoid-double-free-in-label-and-preceden.patch b/gaiconf_init-Avoid-double-free-in-label-and-preceden.patch new file mode 100644 index 0000000000000000000000000000000000000000..7ebc183cfe5c2c5e11ca8a8db56c61cab02ede10 --- /dev/null +++ b/gaiconf_init-Avoid-double-free-in-label-and-preceden.patch @@ -0,0 +1,36 @@ +From 77a34079d8f3d63b61543bf3af93043f8674e4c4 Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +Date: Tue, 3 Aug 2021 21:11:03 +0530 +Subject: [PATCH] gaiconf_init: Avoid double-free in label and precedence lists + +labellist and precedencelist could get freed a second time if there +are allocation failures, so set them to NULL to avoid a double-free. + +Reviewed-by: Arjun Shankar +--- + sysdeps/posix/getaddrinfo.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 838a68f..43dfc67 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -2008,6 +2008,7 @@ gaiconf_init (void) + l = l->next; + } + free_prefixlist (labellist); ++ labellist = NULL; + + /* Sort the entries so that the most specific ones are at + the beginning. */ +@@ -2046,6 +2047,7 @@ gaiconf_init (void) + l = l->next; + } + free_prefixlist (precedencelist); ++ precedencelist = NULL; + + /* Sort the entries so that the most specific ones are at + the beginning. */ +-- +1.8.3.1 + diff --git a/gconv-Do-not-emit-spurious-NUL-character-in-ISO-2022.patch b/gconv-Do-not-emit-spurious-NUL-character-in-ISO-2022.patch new file mode 100644 index 0000000000000000000000000000000000000000..2c546eac2c2f3d9f4660a5779ebe8cc634f4386b --- /dev/null +++ b/gconv-Do-not-emit-spurious-NUL-character-in-ISO-2022.patch @@ -0,0 +1,185 @@ +From ff012870b2c02a62598c04daa1e54632e020fd7d Mon Sep 17 00:00:00 2001 +From: Nikita Popov +Date: Tue, 2 Nov 2021 13:21:42 +0500 +Subject: [PATCH] gconv: Do not emit spurious NUL character in ISO-2022-JP-3 + (bug 28524) + +Bugfix 27256 has introduced another issue: +In conversion from ISO-2022-JP-3 encoding, it is possible +to force iconv to emit extra NUL character on internal state reset. +To do this, it is sufficient to feed iconv with escape sequence +which switches active character set. +The simplified check 'data->__statep->__count != ASCII_set' +introduced by the aforementioned bugfix picks that case and +behaves as if '\0' character has been queued thus emitting it. + +To eliminate this issue, these steps are taken: +* Restore original condition +'(data->__statep->__count & ~7) != ASCII_set'. +It is necessary since bits 0-2 may contain +number of buffered input characters. +* Check that queued character is not NUL. +Similar step is taken for main conversion loop. + +Bundled test case follows following logic: +* Try to convert ISO-2022-JP-3 escape sequence +switching active character set +* Reset internal state by providing NULL as input buffer +* Ensure that nothing has been converted. + +Signed-off-by: Nikita Popov +--- + iconvdata/Makefile | 5 +++- + iconvdata/bug-iconv15.c | 60 +++++++++++++++++++++++++++++++++++++++ + iconvdata/iso-2022-jp-3.c | 28 ++++++++++++------ + 3 files changed, 84 insertions(+), 9 deletions(-) + create mode 100644 iconvdata/bug-iconv15.c + +diff --git a/iconvdata/Makefile b/iconvdata/Makefile +index c216f959..d5507a04 100644 +--- a/iconvdata/Makefile ++++ b/iconvdata/Makefile +@@ -1,4 +1,5 @@ + # Copyright (C) 1997-2021 Free Software Foundation, Inc. ++# Copyright (C) The GNU Toolchain Authors. + # This file is part of the GNU C Library. + + # The GNU C Library is free software; you can redistribute it and/or +@@ -74,7 +75,7 @@ ifeq (yes,$(build-shared)) + tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \ + tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \ + bug-iconv10 bug-iconv11 bug-iconv12 tst-iconv-big5-hkscs-to-2ucs4 \ +- bug-iconv13 bug-iconv14 ++ bug-iconv13 bug-iconv14 bug-iconv15 + ifeq ($(have-thread-library),yes) + tests += bug-iconv3 + endif +@@ -327,6 +328,8 @@ $(objpfx)bug-iconv12.out: $(addprefix $(objpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) + $(objpfx)bug-iconv14.out: $(addprefix $(objpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) ++$(objpfx)bug-iconv15.out: $(addprefix $(objpfx), $(gconv-modules)) \ ++ $(addprefix $(objpfx),$(modules.so)) + + $(objpfx)iconv-test.out: run-iconv-test.sh \ + $(addprefix $(objpfx), $(gconv-modules)) \ +diff --git a/iconvdata/bug-iconv15.c b/iconvdata/bug-iconv15.c +new file mode 100644 +index 00000000..cc04bd03 +--- /dev/null ++++ b/iconvdata/bug-iconv15.c +@@ -0,0 +1,60 @@ ++/* Bug 28524: Conversion from ISO-2022-JP-3 with iconv ++ may emit spurious NUL character on state reset. ++ Copyright (C) The GNU Toolchain Authors. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ char in[] = "\x1b(I"; ++ char *inbuf = in; ++ size_t inleft = sizeof (in) - 1; ++ char out[1]; ++ char *outbuf = out; ++ size_t outleft = sizeof (out); ++ iconv_t cd; ++ ++ cd = iconv_open ("UTF8", "ISO-2022-JP-3"); ++ TEST_VERIFY_EXIT (cd != (iconv_t) -1); ++ ++ /* First call to iconv should alter internal state. ++ Now, JISX0201_Kana_set is selected and ++ state value != ASCII_set. */ ++ TEST_VERIFY (iconv (cd, &inbuf, &inleft, &outbuf, &outleft) != (size_t) -1); ++ ++ /* No bytes should have been added to ++ the output buffer at this point. */ ++ TEST_VERIFY (outbuf == out); ++ TEST_VERIFY (outleft == sizeof (out)); ++ ++ /* Second call shall emit spurious NUL character in unpatched glibc. */ ++ TEST_VERIFY (iconv (cd, NULL, NULL, &outbuf, &outleft) != (size_t) -1); ++ ++ /* No characters are expected to be produced. */ ++ TEST_VERIFY (outbuf == out); ++ TEST_VERIFY (outleft == sizeof (out)); ++ ++ TEST_VERIFY_EXIT (iconv_close (cd) != -1); ++ ++ return 0; ++} ++ ++#include +diff --git a/iconvdata/iso-2022-jp-3.c b/iconvdata/iso-2022-jp-3.c +index c8ba88cd..5fc0c0f7 100644 +--- a/iconvdata/iso-2022-jp-3.c ++++ b/iconvdata/iso-2022-jp-3.c +@@ -1,5 +1,6 @@ + /* Conversion module for ISO-2022-JP-3. + Copyright (C) 1998-2021 Free Software Foundation, Inc. ++ Copyright (C) The GNU Toolchain Authors. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1998, + and Bruno Haible , 2002. +@@ -81,20 +82,31 @@ enum + the output state to the initial state. This has to be done during the + flushing. */ + #define EMIT_SHIFT_TO_INIT \ +- if (data->__statep->__count != ASCII_set) \ ++ if ((data->__statep->__count & ~7) != ASCII_set) \ + { \ + if (FROM_DIRECTION) \ + { \ +- if (__glibc_likely (outbuf + 4 <= outend)) \ ++ uint32_t ch = data->__statep->__count >> 6; \ ++ \ ++ if (__glibc_unlikely (ch != 0)) \ + { \ +- /* Write out the last character. */ \ +- *((uint32_t *) outbuf) = data->__statep->__count >> 6; \ +- outbuf += sizeof (uint32_t); \ +- data->__statep->__count = ASCII_set; \ ++ if (__glibc_likely (outbuf + 4 <= outend)) \ ++ { \ ++ /* Write out the last character. */ \ ++ put32u (outbuf, ch); \ ++ outbuf += 4; \ ++ data->__statep->__count &= 7; \ ++ data->__statep->__count |= ASCII_set; \ ++ } \ ++ else \ ++ /* We don't have enough room in the output buffer. */ \ ++ status = __GCONV_FULL_OUTPUT; \ + } \ + else \ +- /* We don't have enough room in the output buffer. */ \ +- status = __GCONV_FULL_OUTPUT; \ ++ { \ ++ data->__statep->__count &= 7; \ ++ data->__statep->__count |= ASCII_set; \ ++ } \ + } \ + else \ + { \ +-- +2.23.0 + diff --git a/gconv_parseconfdir-Fix-memory-leak.patch b/gconv_parseconfdir-Fix-memory-leak.patch new file mode 100644 index 0000000000000000000000000000000000000000..de306cccbb58dc9dab731c59c05d4337266708fb --- /dev/null +++ b/gconv_parseconfdir-Fix-memory-leak.patch @@ -0,0 +1,37 @@ +From 5f9b78fe35d08739b6da1e5b356786d41116c108 Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +Date: Tue, 3 Aug 2021 21:10:20 +0530 +Subject: [PATCH] gconv_parseconfdir: Fix memory leak + +The allocated `conf` would leak if we have to skip over the file due +to the underlying filesystem not supporting dt_type. + +Reviewed-by: Arjun Shankar +--- + iconv/gconv_parseconfdir.h | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h +index a4153e5..2f06268 100644 +--- a/iconv/gconv_parseconfdir.h ++++ b/iconv/gconv_parseconfdir.h +@@ -153,12 +153,11 @@ gconv_parseconfdir (const char *dir, size_t dir_len) + struct stat64 st; + if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0) + continue; +- if (ent->d_type == DT_UNKNOWN +- && (lstat64 (conf, &st) == -1 +- || !S_ISREG (st.st_mode))) +- continue; + +- found |= read_conf_file (conf, dir, dir_len); ++ if (ent->d_type != DT_UNKNOWN ++ || (lstat64 (conf, &st) != -1 && S_ISREG (st.st_mode))) ++ found |= read_conf_file (conf, dir, dir_len); ++ + free (conf); + } + } +-- +1.8.3.1 + diff --git a/getcwd-Set-errno-to-ERANGE-for-size-1-CVE-2021-3999.patch b/getcwd-Set-errno-to-ERANGE-for-size-1-CVE-2021-3999.patch new file mode 100644 index 0000000000000000000000000000000000000000..6d258a26f4b6f274096ae74857ccb9408932544c --- /dev/null +++ b/getcwd-Set-errno-to-ERANGE-for-size-1-CVE-2021-3999.patch @@ -0,0 +1,355 @@ +From 472e799a5f2102bc0c3206dbd5a801765fceb39c Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +Date: Fri, 21 Jan 2022 23:32:56 +0530 +Subject: [PATCH] getcwd: Set errno to ERANGE for size == 1 (CVE-2021-3999) + +No valid path returned by getcwd would fit into 1 byte, so reject the +size early and return NULL with errno set to ERANGE. This change is +prompted by CVE-2021-3999, which describes a single byte buffer +underflow and overflow when all of the following conditions are met: + +- The buffer size (i.e. the second argument of getcwd) is 1 byte +- The current working directory is too long +- '/' is also mounted on the current working directory + +Sequence of events: + +- In sysdeps/unix/sysv/linux/getcwd.c, the syscall returns ENAMETOOLONG + because the linux kernel checks for name length before it checks + buffer size + +- The code falls back to the generic getcwd in sysdeps/posix + +- In the generic func, the buf[0] is set to '\0' on line 250 + +- this while loop on line 262 is bypassed: + + while (!(thisdev == rootdev && thisino == rootino)) + + since the rootfs (/) is bind mounted onto the directory and the flow + goes on to line 449, where it puts a '/' in the byte before the + buffer. + +- Finally on line 458, it moves 2 bytes (the underflowed byte and the + '\0') to the buf[0] and buf[1], resulting in a 1 byte buffer overflow. + +- buf is returned on line 469 and errno is not set. + +This resolves BZ #28769. + +Reviewed-by: Andreas Schwab +Reviewed-by: Adhemerval Zanella +Signed-off-by: Qualys Security Advisory +Signed-off-by: Siddhesh Poyarekar +(cherry picked from commit 23e0e8f5f1fb5ed150253d986ecccdc90c2dcd5e) +--- + NEWS | 6 + + sysdeps/posix/getcwd.c | 7 + + sysdeps/unix/sysv/linux/Makefile | 7 +- + .../unix/sysv/linux/tst-getcwd-smallbuff.c | 241 ++++++++++++++++++ + 4 files changed, 260 insertions(+), 1 deletion(-) + create mode 100644 sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c + +diff --git a/NEWS b/NEWS +index b4f81c2668..8d7467d2c1 100644 +--- a/NEWS ++++ b/NEWS +@@ -20,6 +20,12 @@ Security related changes: + function could result in a memory leak and potential access of + uninitialized memory. Reported by Qualys. + ++ CVE-2021-3999: Passing a buffer of size exactly 1 byte to the getcwd ++ function may result in an off-by-one buffer underflow and overflow ++ when the current working directory is longer than PATH_MAX and also ++ corresponds to the / directory through an unprivileged mount ++ namespace. Reported by Qualys. ++ + The following bugs are resolved with this release: + + [12889] nptl: Fix race between pthread_kill and thread exit +diff --git a/sysdeps/posix/getcwd.c b/sysdeps/posix/getcwd.c +index 13680026ff..b6984a382c 100644 +--- a/sysdeps/posix/getcwd.c ++++ b/sysdeps/posix/getcwd.c +@@ -187,6 +187,13 @@ __getcwd_generic (char *buf, size_t size) + size_t allocated = size; + size_t used; + ++ /* A size of 1 byte is never useful. */ ++ if (allocated == 1) ++ { ++ __set_errno (ERANGE); ++ return NULL; ++ } ++ + #if HAVE_MINIMALLY_WORKING_GETCWD + /* If AT_FDCWD is not defined, the algorithm below is O(N**2) and + this is much slower than the system getcwd (at least on +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index 76ad06361c..9380d3848d 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -331,7 +331,12 @@ sysdep_routines += xstatconv internal_statvfs \ + + sysdep_headers += bits/fcntl-linux.h + +-tests += tst-fallocate tst-fallocate64 tst-o_path-locks ++tests += \ ++ tst-fallocate \ ++ tst-fallocate64 \ ++ tst-getcwd-smallbuff \ ++ tst-o_path-locks \ ++# tests + endif + + ifeq ($(subdir),elf) +diff --git a/sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c b/sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c +new file mode 100644 +index 0000000000..d460d6e766 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c +@@ -0,0 +1,241 @@ ++/* Verify that getcwd returns ERANGE for size 1 byte and does not underflow ++ buffer when the CWD is too long and is also a mount target of /. See bug ++ #28769 or CVE-2021-3999 for more context. ++ Copyright The GNU Toolchain Authors. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static char *base; ++#define BASENAME "tst-getcwd-smallbuff" ++#define MOUNT_NAME "mpoint" ++static int sockfd[2]; ++ ++static void ++do_cleanup (void) ++{ ++ support_chdir_toolong_temp_directory (base); ++ TEST_VERIFY_EXIT (rmdir (MOUNT_NAME) == 0); ++ free (base); ++} ++ ++static void ++send_fd (const int sock, const int fd) ++{ ++ struct msghdr msg = {0}; ++ union ++ { ++ struct cmsghdr hdr; ++ char buf[CMSG_SPACE (sizeof (int))]; ++ } cmsgbuf = {0}; ++ struct cmsghdr *cmsg; ++ struct iovec vec; ++ char ch = 'A'; ++ ssize_t n; ++ ++ msg.msg_control = &cmsgbuf.buf; ++ msg.msg_controllen = sizeof (cmsgbuf.buf); ++ ++ cmsg = CMSG_FIRSTHDR (&msg); ++ cmsg->cmsg_len = CMSG_LEN (sizeof (int)); ++ cmsg->cmsg_level = SOL_SOCKET; ++ cmsg->cmsg_type = SCM_RIGHTS; ++ memcpy (CMSG_DATA (cmsg), &fd, sizeof (fd)); ++ ++ vec.iov_base = &ch; ++ vec.iov_len = 1; ++ msg.msg_iov = &vec; ++ msg.msg_iovlen = 1; ++ ++ while ((n = sendmsg (sock, &msg, 0)) == -1 && errno == EINTR); ++ ++ TEST_VERIFY_EXIT (n == 1); ++} ++ ++static int ++recv_fd (const int sock) ++{ ++ struct msghdr msg = {0}; ++ union ++ { ++ struct cmsghdr hdr; ++ char buf[CMSG_SPACE(sizeof(int))]; ++ } cmsgbuf = {0}; ++ struct cmsghdr *cmsg; ++ struct iovec vec; ++ ssize_t n; ++ char ch = '\0'; ++ int fd = -1; ++ ++ vec.iov_base = &ch; ++ vec.iov_len = 1; ++ msg.msg_iov = &vec; ++ msg.msg_iovlen = 1; ++ ++ msg.msg_control = &cmsgbuf.buf; ++ msg.msg_controllen = sizeof (cmsgbuf.buf); ++ ++ while ((n = recvmsg (sock, &msg, 0)) == -1 && errno == EINTR); ++ if (n != 1 || ch != 'A') ++ return -1; ++ ++ cmsg = CMSG_FIRSTHDR (&msg); ++ if (cmsg == NULL) ++ return -1; ++ if (cmsg->cmsg_type != SCM_RIGHTS) ++ return -1; ++ memcpy (&fd, CMSG_DATA (cmsg), sizeof (fd)); ++ if (fd < 0) ++ return -1; ++ return fd; ++} ++ ++static int ++child_func (void * const arg) ++{ ++ xclose (sockfd[0]); ++ const int sock = sockfd[1]; ++ char ch; ++ ++ TEST_VERIFY_EXIT (read (sock, &ch, 1) == 1); ++ TEST_VERIFY_EXIT (ch == '1'); ++ ++ if (mount ("/", MOUNT_NAME, NULL, MS_BIND | MS_REC, NULL)) ++ FAIL_EXIT1 ("mount failed: %m\n"); ++ const int fd = xopen ("mpoint", ++ O_RDONLY | O_PATH | O_DIRECTORY | O_NOFOLLOW, 0); ++ ++ send_fd (sock, fd); ++ xclose (fd); ++ ++ TEST_VERIFY_EXIT (read (sock, &ch, 1) == 1); ++ TEST_VERIFY_EXIT (ch == 'a'); ++ ++ xclose (sock); ++ return 0; ++} ++ ++static void ++update_map (char * const mapping, const char * const map_file) ++{ ++ const size_t map_len = strlen (mapping); ++ ++ const int fd = xopen (map_file, O_WRONLY, 0); ++ xwrite (fd, mapping, map_len); ++ xclose (fd); ++} ++ ++static void ++proc_setgroups_write (const long child_pid, const char * const str) ++{ ++ const size_t str_len = strlen(str); ++ ++ char setgroups_path[sizeof ("/proc//setgroups") + INT_STRLEN_BOUND (long)]; ++ ++ snprintf (setgroups_path, sizeof (setgroups_path), ++ "/proc/%ld/setgroups", child_pid); ++ ++ const int fd = open (setgroups_path, O_WRONLY); ++ ++ if (fd < 0) ++ { ++ TEST_VERIFY_EXIT (errno == ENOENT); ++ FAIL_UNSUPPORTED ("/proc/%ld/setgroups not found\n", child_pid); ++ } ++ ++ xwrite (fd, str, str_len); ++ xclose(fd); ++} ++ ++static char child_stack[1024 * 1024]; ++ ++int ++do_test (void) ++{ ++ base = support_create_and_chdir_toolong_temp_directory (BASENAME); ++ ++ xmkdir (MOUNT_NAME, S_IRWXU); ++ atexit (do_cleanup); ++ ++ TEST_VERIFY_EXIT (socketpair (AF_UNIX, SOCK_STREAM, 0, sockfd) == 0); ++ pid_t child_pid = xclone (child_func, NULL, child_stack, ++ sizeof (child_stack), ++ CLONE_NEWUSER | CLONE_NEWNS | SIGCHLD); ++ ++ xclose (sockfd[1]); ++ const int sock = sockfd[0]; ++ ++ char map_path[sizeof ("/proc//uid_map") + INT_STRLEN_BOUND (long)]; ++ char map_buf[sizeof ("0 1") + INT_STRLEN_BOUND (long)]; ++ ++ snprintf (map_path, sizeof (map_path), "/proc/%ld/uid_map", ++ (long) child_pid); ++ snprintf (map_buf, sizeof (map_buf), "0 %ld 1", (long) getuid()); ++ update_map (map_buf, map_path); ++ ++ proc_setgroups_write ((long) child_pid, "deny"); ++ snprintf (map_path, sizeof (map_path), "/proc/%ld/gid_map", ++ (long) child_pid); ++ snprintf (map_buf, sizeof (map_buf), "0 %ld 1", (long) getgid()); ++ update_map (map_buf, map_path); ++ ++ TEST_VERIFY_EXIT (send (sock, "1", 1, MSG_NOSIGNAL) == 1); ++ const int fd = recv_fd (sock); ++ TEST_VERIFY_EXIT (fd >= 0); ++ TEST_VERIFY_EXIT (fchdir (fd) == 0); ++ ++ static char buf[2 * 10 + 1]; ++ memset (buf, 'A', sizeof (buf)); ++ ++ /* Finally, call getcwd and check if it resulted in a buffer underflow. */ ++ char * cwd = getcwd (buf + sizeof (buf) / 2, 1); ++ TEST_VERIFY (cwd == NULL); ++ TEST_VERIFY (errno == ERANGE); ++ ++ for (int i = 0; i < sizeof (buf); i++) ++ if (buf[i] != 'A') ++ { ++ printf ("buf[%d] = %02x\n", i, (unsigned int) buf[i]); ++ support_record_failure (); ++ } ++ ++ TEST_VERIFY_EXIT (send (sock, "a", 1, MSG_NOSIGNAL) == 1); ++ xclose (sock); ++ TEST_VERIFY_EXIT (xwaitpid (child_pid, NULL, 0) == child_pid); ++ ++ return 0; ++} ++ ++#define CLEANUP_HANDLER do_cleanup ++#include +-- +2.27.0 + diff --git a/gethosts-Remove-unused-argument-_type.patch b/gethosts-Remove-unused-argument-_type.patch new file mode 100644 index 0000000000000000000000000000000000000000..1fb60e7c2db97c282a8ae87745083d32c72eebc0 --- /dev/null +++ b/gethosts-Remove-unused-argument-_type.patch @@ -0,0 +1,44 @@ +From b17e842a60819098d2a203ecc8b8371b7e1d6c65 Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +Date: Wed, 4 Aug 2021 02:21:01 +0530 +Subject: [PATCH] gethosts: Remove unused argument _type + +The generated code is unchanged. +--- + sysdeps/posix/getaddrinfo.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 43dfc67..9f1cde2 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -239,7 +239,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, + return true; + } + +-#define gethosts(_family, _type) \ ++#define gethosts(_family) \ + { \ + struct hostent th; \ + char *localcanon = NULL; \ +@@ -829,7 +829,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + if (req->ai_family == AF_INET6 + || req->ai_family == AF_UNSPEC) + { +- gethosts (AF_INET6, struct in6_addr); ++ gethosts (AF_INET6); + no_inet6_data = no_data; + inet6_status = status; + } +@@ -841,7 +841,7 @@ gaih_inet (const char *name, const struct gaih_service *service, + know we are not going to need them. */ + && ((req->ai_flags & AI_ALL) || !got_ipv6))) + { +- gethosts (AF_INET, struct in_addr); ++ gethosts (AF_INET); + + if (req->ai_family == AF_INET) + { +-- +1.8.3.1 + diff --git a/glibc-1070416.patch b/glibc-1070416.patch deleted file mode 100644 index 0975e0fa98e39c499f61f933d5c2040c54d5835c..0000000000000000000000000000000000000000 --- a/glibc-1070416.patch +++ /dev/null @@ -1,38 +0,0 @@ -Short description: Add syslog.target dependency. -Author(s): Fedora glibc team -Origin: PATCH -Bug-Fedora: #1070416 -Upstream status: not-needed - -Fedora-specific changes to the nscd.service file. -See also: glibc-nscd-sysconfig.patch. - ---- a/nscd/nscd.service -+++ b/nscd/nscd.service -@@ -2,6 +2,7 @@ - - [Unit] - Description=Name Service Cache Daemon -+After=syslog.target - - [Service] - Type=forking -@@ -17,3 +18,4 @@ - - [Install] - WantedBy=multi-user.target -+Also=nscd.socket -diff --git a/nscd/nscd.socket b/nscd/nscd.socket -new file mode 100644 -index 0000000..7e512d5 ---- /dev/null -+++ b/nscd/nscd.socket -@@ -0,0 +1,8 @@ -+[Unit] -+Description=Name Service Cache Daemon Socket -+ -+[Socket] -+ListenDatagram=/var/run/nscd/socket -+ -+[Install] -+WantedBy=sockets.target diff --git a/glibc.spec b/glibc.spec index 6f0b8633131383d91900c7a53fbf4a01a20d98d5..ba4360355dcfa5366a11f8cd718deee93526542d 100644 --- a/glibc.spec +++ b/glibc.spec @@ -1,4 +1,5 @@ -%global __filter_GLIBC_PRIVATE 1 +%global __requires_exclude GLIBC_PRIVATE +%global __provides_exclude GLIBC_PRIVATE %define rpm_ver_major %(eval "echo `rpm -q rpm |cut -d '-' -f2 |cut -d. -f1`") %define rpm_ver_minor %(eval "echo `rpm -q rpm |cut -d '-' -f2 |cut -d. -f2`") @@ -27,11 +28,13 @@ # - Default: Always run valgrind tests if there is architecture support. ############################################################################## %bcond_without testsuite -%bcond_without benchtests +%bcond_with benchtests %bcond_with bootstrap %bcond_with werror %bcond_without docs -%bcond_with libpthreadcond +%ifarch x86_64 aarch64 +%bcond_without compat_2_17 +%endif %ifarch %{valgrind_arches} %bcond_without valgrind @@ -46,6 +49,9 @@ %undefine with_valgrind %endif +# Only some architectures have static PIE support +%define pie_arches %{ix86} x86_64 aarch64 + %define enablekernel 3.2 %define target %{_target_cpu}-%{_vendor}-linux %ifarch %{arm} @@ -60,13 +66,12 @@ ############################################################################## Name: glibc Version: 2.34 -Release: 1 +Release: 71 Summary: The GNU libc libraries License: %{all_license} URL: http://www.gnu.org/software/glibc/ Source0: https://ftp.gnu.org/gnu/glibc/%{name}-%{version}.tar.xz -Source1: nscd.conf Source2: nsswitch.conf Source3: bench.mk Source4: glibc-bench-compare @@ -74,19 +79,164 @@ Source5: LanguageList Source6: LicenseList Source7: replace_same_file_to_hard_link.py -Patch0: glibc-1070416.patch -Patch1: glibc-c-utf8-locale.patch +%if %{with testsuite} +Source8: testsuite_whitelist +%endif -#Patch9000: turn-REP_STOSB_THRESHOLD-from-2k-to-1M.patch +Patch1: glibc-c-utf8-locale.patch +Patch2: backport-CVE-2021-38604-0001-librt-add-test-bug-28213.patch +Patch3: backport-CVE-2021-38604-0002-librt-fix-NULL-pointer-dereference-bug-28213.patch +Patch4: copy_and_spawn_sgid-Avoid-double-calls-to-close.patch +Patch5: gaiconf_init-Avoid-double-free-in-label-and-preceden.patch +Patch6: gconv_parseconfdir-Fix-memory-leak.patch +Patch7: gethosts-Remove-unused-argument-_type.patch +Patch8: iconv_charmap-Close-output-file-when-done.patch +Patch9: ldconfig-avoid-leak-on-empty-paths-in-config-file.patch +Patch10: Linux-Fix-fcntl-ioctl-prctl-redirects-for-_TIME_BITS.patch +Patch11: nis-Fix-leak-on-realloc-failure-in-nis_getnames-BZ-2.patch +Patch12: rt-Set-the-correct-message-queue-for-tst-mqueue10.patch +Patch13: 1-5-AArch64-Improve-A64FX-memset-for-small-sizes.patch +Patch14: 2-5-AArch64-Improve-A64FX-memset-for-large-sizes.patch +Patch15: 3-5-AArch64-Improve-A64FX-memset-for-remaining-bytes.patch +Patch16: 4-5-AArch64-Improve-A64FX-memset-by-removing-unroll3.patch +Patch17: 5-5-AArch64-Improve-A64FX-memset-medium-loops.patch +Patch18: elf-Unconditionally-use-__ehdr_start.patch +Patch19: aarch64-Make-elf_machine_-load_address-dynamic-robus.patch +Patch20: mtrace-Use-a-static-buffer-for-printing-BZ-25947.patch +Patch21: time-Fix-overflow-itimer-tests-on-32-bit-systems.patch +Patch22: arm-Simplify-elf_machine_-load_address-dynamic.patch +Patch23: elf-Drop-elf-tls-macros.h-in-favor-of-__thread-and-t.patch +Patch24: elf-Fix-missing-colon-in-LD_SHOW_AUXV-output-BZ-2825.patch +Patch25: Remove-sysdeps-tls-macros.h.patch +Patch26: riscv-Drop-reliance-on-_GLOBAL_OFFSET_TABLE_-0.patch +Patch27: x86_64-Simplify-elf_machine_-load_address-dynamic.patch +Patch28: x86-fix-Autoconf-caching-of-instruction-support-chec.patch +Patch29: Update-string-test-memmove.c-to-cover-16KB-copy.patch +Patch30: x86-64-Optimize-load-of-all-bits-set-into-ZMM-regist.patch +Patch31: mtrace-Fix-output-with-PIE-and-ASLR-BZ-22716.patch +Patch32: rtld-copy-terminating-null-in-tunables_strdup-bug-28.patch +Patch33: Use-__executable_start-as-the-lowest-address-for-pro.patch +Patch34: x86-64-Use-testl-to-check-__x86_string_control.patch +Patch35: AArch64-Update-A64FX-memset-not-to-degrade-at-16KB.patch +Patch36: support-Add-support_wait_for_thread_exit.patch +Patch37: nptl-pthread_kill-pthread_cancel-should-not-fail-aft.patch +Patch38: nptl-Fix-race-between-pthread_kill-and-thread-exit-b.patch +Patch39: nptl-pthread_kill-needs-to-return-ESRCH-for-old-prog.patch +Patch40: nptl-Fix-type-of-pthread_mutexattr_getrobust_np-pthr.patch +Patch41: nptl-Avoid-setxid-deadlock-with-blocked-signals-in-t.patch +Patch42: nptl-pthread_kill-must-send-signals-to-a-specific-th.patch +Patch43: iconvconfig-Fix-behaviour-with-prefix-BZ-28199.patch +Patch44: gconv-Do-not-emit-spurious-NUL-character-in-ISO-2022.patch +Patch45: elf-Avoid-deadlock-between-pthread_create-and-ctors-.patch +Patch46: ld.so-Replace-DL_RO_DYN_SECTION-with-dl_relocate_ld-.patch +Patch47: ld.so-Initialize-bootstrap_map.l_ld_readonly-BZ-2834.patch +Patch48: Avoid-warning-overriding-recipe-for-.-tst-ro-dynamic.patch +Patch49: posix-Fix-attribute-access-mode-on-getcwd-BZ-27476.patch +Patch50: Linux-Simplify-__opensock-and-fix-race-condition-BZ-.patch +Patch51: linux-Simplify-get_nprocs.patch +Patch52: misc-Add-__get_nprocs_sched.patch +Patch53: linux-Revert-the-use-of-sched_getaffinity-on-get_npr.patch +Patch54: pthread-tst-cancel28-Fix-barrier-re-init-race-condit.patch +Patch55: support-Add-support_open_dev_null_range.patch +Patch56: Use-support_open_dev_null_range-io-tst-closefrom-mis.patch +Patch57: Fix-failing-nss-tst-nss-files-hosts-long-with-local-.patch +Patch58: nptl-Add-one-more-barrier-to-nptl-tst-create1.patch +Patch59: io-Fix-ftw-internal-realloc-buffer-BZ-28126.patch +Patch60: Do-not-define-tgmath.h-fmaxmag-fminmag-macros-for-C2.patch +Patch61: ld.so-Don-t-fill-the-DT_DEBUG-entry-in-ld.so-BZ-2812.patch +Patch62: elf-Replace-nsid-with-args.nsid-BZ-27609.patch +Patch63: support-Also-return-fd-when-it-is-0.patch +Patch64: elf-Earlier-missing-dynamic-segment-check-in-_dl_map.patch +Patch65: Handle-NULL-input-to-malloc_usable_size-BZ-28506.patch +Patch66: intl-plural.y-Avoid-conflicting-declarations-of-yyer.patch +Patch67: linux-Use-proc-stat-fallback-for-__get_nprocs_conf-B.patch +Patch68: nptl-Do-not-set-signal-mask-on-second-setjmp-return-.patch +Patch69: nss-Use-files-dns-as-the-default-for-the-hosts-datab.patch +Patch70: timex-Use-64-bit-fields-on-32-bit-TIMESIZE-64-system.patch +Patch71: AArch64-Check-for-SVE-in-ifuncs-BZ-28744.patch +Patch72: Fix-subscript-error-with-odd-TZif-file-BZ-28338.patch +Patch73: timezone-handle-truncated-timezones-from-tzcode-2021.patch +Patch74: timezone-test-case-for-BZ-28707.patch +Patch75: socket-Add-the-__sockaddr_un_set-function.patch +Patch76: CVE-2022-23219-Buffer-overflow-in-sunrpc-clnt_create.patch +Patch77: sunrpc-Test-case-for-clnt_create-unix-buffer-overflo.patch +Patch78: CVE-2022-23218-Buffer-overflow-in-sunrpc-svcunix_cre.patch +Patch79: support-Add-check-for-TID-zero-in-support_wait_for_t.patch +Patch80: support-Add-helpers-to-create-paths-longer-than-PATH.patch +Patch81: stdlib-Sort-tests-in-Makefile.patch +Patch82: stdlib-Fix-formatting-of-tests-list-in-Makefile.patch +Patch83: realpath-Set-errno-to-ENAMETOOLONG-for-result-larger.patch +Patch84: tst-realpath-toolong-Fix-hurd-build.patch +Patch85: getcwd-Set-errno-to-ERANGE-for-size-1-CVE-2021-3999.patch +Patch86: Linux-Detect-user-namespace-support-in-io-tst-getcwd.patch +Patch87: Disable-debuginfod-in-printer-tests-BZ-28757.patch +Patch88: i386-Remove-broken-CAN_USE_REGISTER_ASM_EBP-bug-2877.patch +Patch89: x86-use-default-cache-size-if-it-cannot-be-determine.patch +Patch90: x86-Fix-__wcsncmp_avx2-in-strcmp-avx2.S-BZ-28755.patch +Patch91: x86-Fix-__wcsncmp_evex-in-strcmp-evex.S-BZ-28755.patch +Patch92: linux-__get_nprocs_sched-do-not-feed-CPU_COUNT_S-wit.patch +Patch93: elf-Sort-tests-and-modules-names.patch +Patch94: elf-Add-a-comment-after-trailing-backslashes.patch +Patch95: elf-Makefile-Reflow-and-sort-most-variable-assignmen.patch +Patch96: Fix-glibc-2.34-ABI-omission-missing-GLIBC_2.34-in-dy.patch +Patch97: x86-Black-list-more-Intel-CPUs-for-TSX-BZ-27398.patch +Patch98: x86-Use-CHECK_FEATURE_PRESENT-to-check-HLE-BZ-27398.patch +Patch99: support-Add-support_socket_so_timestamp_time64.patch +Patch100: linux-Fix-ancillary-64-bit-time-timestamp-conversion.patch +Patch101: Linux-Only-generate-64-bit-timestamps-for-64-bit-tim.patch +Patch102: socket-Do-not-use-AF_NETLINK-in-__opensock.patch +Patch103: tst-socket-timestamp-compat.c-Check-__TIMESIZE-BZ-28.patch +Patch104: linux-Fix-missing-__convert_scm_timestamps-BZ-28860.patch +Patch105: linux-fix-accuracy-of-get_nprocs-and-get_nprocs_conf.patch +Patch106: rseq-nptl-Add-thread_pointer.h-for-defining-__thread_poin.patch +Patch107: rseq-nptl-Introduce-tcb-access.h-for-THREAD_-accessors.patch +Patch108: rseq-nptl-Introduce-THREAD_GETMEM_VOLATILE.patch +Patch109: rseq-nptl-Add-rseq-registration.patch +Patch110: rseq-Linux-Use-rseq-to-accelerate-sched_getcpu.patch +Patch111: rseq-nptl-Add-glibc.pthread.rseq-tunable-to-control-rseq-.patch +Patch112: rseq-nptl-Add-public-rseq-symbols-and-sys-rseq.h.patch +Patch113: rseq-nptl-rseq-failure-after-registration-on-main-thread-.patch +Patch114: rseq-Linux-Use-ptrdiff_t-for-__rseq_offset.patch +Patch115: x86-Fallback-str-wcs-cmp-RTM-in-the-ncmp-overflow-ca.patch +Patch116: x86-Test-wcscmp-RTM-in-the-wcsncmp-overflow-case-BZ-.patch +Patch117: x86-Fix-TEST_NAME-to-make-it-a-string-in-tst-strncmp.patch +Patch118: Add-PTRACE_GET_RSEQ_CONFIGURATION-from-Linux-5.13-to.patch +Patch119: malloc-hugepage-0001-malloc-Add-madvise-support-for-Transparent-Huge-Page.patch +Patch120: malloc-hugepage-0002-malloc-Add-THP-madvise-support-for-sbrk.patch +Patch121: malloc-hugepage-0003-malloc-Move-mmap-logic-to-its-own-function.patch +Patch122: malloc-hugepage-0004-malloc-Add-Huge-Page-support-for-mmap.patch +Patch123: malloc-hugepage-0005-malloc-Add-Huge-Page-support-to-arenas.patch +Patch124: malloc-hugepage-0006-malloc-Move-MORECORE-fallback-mmap-to-sysmalloc_mmap.patch +Patch125: malloc-hugepage-0007-malloc-Enable-huge-page-support-on-main-arena.patch + +Patch9000: turn-default-value-of-x86_rep_stosb_threshold_form_2K_to_1M.patch Patch9001: delete-no-hard-link-to-avoid-all_language-package-to.patch -#Patch9002: build-extra-libpthreadcond-so.patch - +Patch9002: 0001-add-base-files-for-libphtread-condition-family.patch +Patch9003: 0002-add-header-files-for-libphtread_2_17_so.patch +Patch9004: 0003-add-build-script-and-files-of-libpthread_2_17_so.patch +Patch9005: 0004-add-two-header-files-with-some-deleted-macros.patch +Patch9006: 0005-add-pthread-functions_h.patch +Patch9007: 0006-add-elsion-function-which-moved-to-libc-in-glibc-2.34.patch +Patch9008: 0007-add-lowlevellock_2_17_c.patch +Patch9009: 0008-add-pause_nocancel_2_17.patch +Patch9010: 0009-add-unwind-with-longjmp.patch +Patch9011: delete-check-installed-headers-c-and-check-installed.patch +Patch9012: fix-CVE-2019-1010023.patch +Patch9013: fix-tst-glibcsyscalls-due-to-kernel-reserved-some-sy.patch +Patch9014: use-region-to-instead-of-country-for-extract-timezon.patch +Patch9015: strcmp-delete-align-for-loop_aligned.patch +Patch9016: 0001-elf-dynamic-linker-load-shared-object-use-hugepage-a.patch +Patch9017: 0002-elf-ld.so-add-testcase-for-ld.so-load-shared-object-.patch +Patch9018: 0003-elf-ld.so-use-special-mmap-for-hugepage-to-get-symbo.patch +Patch9019: malloc-use-__get_nprocs-replace-__get_nprocs_sched.patch + +Obsoletes: nscd < 2.35 Provides: ldconfig rtld(GNU_HASH) bundled(gnulib) BuildRequires: audit-libs-devel >= 1.1.3, sed >= 3.95, libcap-devel, gettext BuildRequires: procps-ng, util-linux, gawk, systemtap-sdt-devel, systemd, python3 BuildRequires: make >= 4.0, bison >= 2.7, binutils >= 2.30-17, gcc >= 7.2.1-6 -BuildRequires: m4 gcc_secure +BuildRequires: m4 gcc_secure chrpath %if %{without bootstrap} BuildRequires: gd-devel libpng-devel zlib-devel @@ -194,6 +344,20 @@ Requires: %{name}-common = %{version}-%{release} The locale-source package contains all language packs which are built custom locales +############################################################################## +# glibc "locale-archive" sub-package +############################################################################## +%package locale-archive +Summary: The locale-archive of glibc +Requires: %{name} = %{version}-%{release} +Requires: %{name}-common = %{version}-%{release} + +%description locale-archive +The locale-archive sub package contains the locale-archive. In the past, +this file is provided in "glibc-common".Now, we provide basic language support +in "glibc-common", but if you need a customized language, you can extract +it from the "local-archive". + ############################################################################## # glibc "devel" sub-package ############################################################################## @@ -201,7 +365,6 @@ locales Summary: The devel for %{name} Requires: %{name} = %{version}-%{release} Requires: libgcc%{_isa} -Requires(pre): info Requires(pre): kernel-headers Requires(pre): coreutils Requires: kernel-headers >= 3.2 @@ -225,24 +388,6 @@ The glibc-devel package contains the object files necessary for developing programs which use the standard C libraries. Besides, it contains the headers. Thus, it is necessory to install glibc-devel if you ned develop programs. -############################################################################## -# glibc "nscd" sub-package -############################################################################## -%package -n nscd -Summary: Name caching service daemon. -Requires: %{name} = %{version}-%{release} -%if %{without bootstrap} -Requires: libselinux >= 1.17.10-1 -%endif -Requires: audit-libs >= 1.1.3 -Requires(pre): shadow-utils, coreutils -Requires: systemd -Requires(postun): shadow-utils - -%description -n nscd -The nscd package is able to daemon caches name service lookups and improve -the performance with LDAP. - ############################################################################## # nss modules sub-package ############################################################################## @@ -313,39 +458,6 @@ Obsoletes: %{name}-utils = 2.28 This package provides memusage, a memory usage profiler, mtrace, a memory leak tracer and xtrace, a function call tracer, all of which is not necessory for you. -############################################################################## -# glibc debuginfo sub-package -############################################################################## -%if 0%{?_enable_debug_packages} -%define debug_package %{nil} -%define __debug_install_post %{nil} -%global __debug_package 1 - -%undefine _debugsource_packages -%undefine _debuginfo_subpackages -%undefine _unique_debug_names -%undefine _unique_debug_srcs - -%package debuginfo -Summary: Debug information for %{name} -AutoReqProv: no - -%description debuginfo -This package provides debug information for package %{name}. -Debug information is useful when developing applications that use this -package or when debugging this package. - -%package debugsource -Summary: Debug source for %{name} -AutoReqProv: no - -%description debugsource -This package provides debug sources for package %{name}. -Debug sources are useful when developing applications that use this -package or when debugging this package. - -%endif # 0%{?_enable_debug_packages} - ############################################################################## # glibc help sub-package ############################################################################## @@ -355,7 +467,19 @@ Buildarch: noarch Requires: man info %description help -This package provides al doc and man files of %{name} +This package provides all doc,man and info files of %{name} + +############################################################################## +# glibc compat-2.17 sub-package +############################################################################## +%if %{with compat_2_17} +%package compat-2.17 +Summary: provides pthread library with glibc-2.17 + +%description compat-2.17 +This subpackage to provide the function of the glibc-2.17 pthread library. +Currently, provide pthread_condition function.. +%endif ############################################################################## # Prepare for the build. @@ -423,9 +547,13 @@ pushd $builddir --enable-bind-now \ --build=%{target} \ --enable-stack-protector=strong \ -%ifarch %{x86_arches} +%ifarch %{pie_arches} %if 0%{?gcc_version} >= 8 --enable-static-pie \ +%endif +%endif +%ifarch %{x86_arches} +%if 0%{?gcc_version} >= 8 --enable-cet \ %endif %endif @@ -444,18 +572,19 @@ pushd $builddir %if 0%{rpm_version_ge_412} --disable-crypt \ %endif - || + --disable-build-nscd \ + --disable-nscd || { cat config.log; false; } make %{?_smp_mflags} -O -r %{glibc_make_flags} popd ############################################################################## -# Build libpthreadcond +# Build libpthread-2.17.so ############################################################################## -%if %{with libpthreadcond} +%if %{with compat_2_17} cd nptl_2_17 - sh build_libpthreadcondso.sh %{_target_cpu} $builddir + sh build_libpthread-2.17.so.sh %{_target_cpu} $builddir cd .. %endif @@ -472,10 +601,6 @@ done make %{?_smp_mflags} install_root=$RPM_BUILD_ROOT install -C build-%{target} -%if %{with libpthreadcond} - cp build-%{target}/nptl/libpthreadcond.so $RPM_BUILD_ROOT%{_libdir} -%endif - pushd build-%{target} make %{?_smp_mflags} install_root=$RPM_BUILD_ROOT \ @@ -523,40 +648,34 @@ $olddir/build-%{target}/elf/ld.so \ --prefix $RPM_BUILD_ROOT --add-to-archive \ eo *_* %{find_lang} libc +# In the past, locale-archive is provided by common. +# In the current version, locale-archive is provided by locale-archive. +# Due to the change of the packing mode, the locale-archive fails to be +# replaced during the upgrade. Therefore, a backup file is required to +# replace the locale-archive. +ln locale-archive locale-archive.update popd mv $RPM_BUILD_ROOT%{_prefix}/lib/locale/libc.lang . # Install configuration files for services install -p -m 644 %{SOURCE2} $RPM_BUILD_ROOT/etc/nsswitch.conf -# This is for ncsd - in glibc 2.2 -install -m 644 nscd/nscd.conf $RPM_BUILD_ROOT/etc -mkdir -p $RPM_BUILD_ROOT%{_tmpfilesdir} -install -m 644 %{SOURCE1} %{buildroot}%{_tmpfilesdir} -mkdir -p $RPM_BUILD_ROOT/lib/systemd/system -install -m 644 nscd/nscd.service nscd/nscd.socket $RPM_BUILD_ROOT/lib/systemd/system +# This is for compat-2.17 +%if %{with compat_2_17} +install -p -m 755 build-%{target}/nptl/libpthread-2.17.so $RPM_BUILD_ROOT%{_libdir} +%endif # Include ld.so.conf echo 'include ld.so.conf.d/*.conf' > $RPM_BUILD_ROOT/etc/ld.so.conf truncate -s 0 $RPM_BUILD_ROOT/etc/ld.so.cache chmod 644 $RPM_BUILD_ROOT/etc/ld.so.conf mkdir -p $RPM_BUILD_ROOT/etc/ld.so.conf.d -mkdir -p $RPM_BUILD_ROOT/etc/sysconfig -truncate -s 0 $RPM_BUILD_ROOT/etc/sysconfig/nscd truncate -s 0 $RPM_BUILD_ROOT/etc/gai.conf # Include %{_libdir}/gconv/gconv-modules.cache truncate -s 0 $RPM_BUILD_ROOT%{_libdir}/gconv/gconv-modules.cache chmod 644 $RPM_BUILD_ROOT%{_libdir}/gconv/gconv-modules.cache -# Install debug copies of unstripped static libraries -%if 0%{?_enable_debug_packages} -mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/debug%{_libdir} -cp -a $RPM_BUILD_ROOT%{_libdir}/*.a \ - $RPM_BUILD_ROOT%{_prefix}/lib/debug%{_libdir}/ -rm -f $RPM_BUILD_ROOT%{_prefix}/lib/debug%{_libdir}/*_p.a -%endif - # Remove any zoneinfo files; they are maintained by tzdata. rm -rf $RPM_BUILD_ROOT%{_prefix}/share/zoneinfo @@ -602,10 +721,6 @@ popd rm -f $RPM_BUILD_ROOT%{_infodir}/dir %endif -mkdir -p $RPM_BUILD_ROOT/var/{db,run}/nscd -touch $RPM_BUILD_ROOT/var/{db,run}/nscd/{passwd,group,hosts,services} -touch $RPM_BUILD_ROOT/var/run/nscd/{socket,nscd.pid} - mkdir -p $RPM_BUILD_ROOT%{_libdir} mv -f $RPM_BUILD_ROOT/%{_lib}/lib{pcprofile,memusage}.so \ $RPM_BUILD_ROOT%{_libdir} @@ -634,13 +749,15 @@ touch master.filelist touch glibc.filelist touch common.filelist touch devel.filelist -touch nscd.filelist touch nss_modules.filelist touch nss-devel.filelist touch libnsl.filelist touch debugutils.filelist touch benchtests.filelist -touch debuginfo.filelist +touch help.filelist +%if %{with compat_2_17} +touch compat-2.17.filelist +%endif { find $RPM_BUILD_ROOT \( -type f -o -type l \) \ @@ -666,7 +783,10 @@ touch debuginfo.filelist -e '\,.*/share/i18n/locales/.*,d' \ -e '\,.*/share/i18n/charmaps/.*,d' \ -e '\,.*/etc/\(localtime\|nsswitch.conf\|ld\.so\.conf\|ld\.so\.cache\|default\|rpc\|gai\.conf\),d' \ - -e '\,.*/%{_libdir}/lib\(pcprofile\|memusage\)\.so,d' \ + -e '\,.*%{_libdir}/lib\(pcprofile\|memusage\)\.so,d' \ +%if %{with compat_2_17} + -e '\,.*%{_libdir}/libpthread-2.17.so,d' \ +%endif -e '\,.*/bin/\(memusage\|mtrace\|xtrace\|pcprofiledump\),d' } | sort > master.filelist @@ -683,7 +803,6 @@ cat master.filelist \ -e '%{_libdir}/lib.*\.a' \ -e '%{_libdir}/.*\.o' \ -e '%{_libdir}/lib.*\.so' \ - -e 'nscd' \ -e '%{_prefix}/bin' \ -e '%{_prefix}/lib/locale' \ -e '%{_prefix}/sbin/[^i]' \ @@ -701,19 +820,16 @@ for module in compat files dns; do -e "/libnss_$module(\.so\.[0-9.]+|-[0-9.]+\.so)$" \ >> glibc.filelist done -grep -e "libmemusage.so" -e "libpcprofile.so" master.filelist >> glibc.filelist -%if %{with libpthreadcond} - echo "%{_libdir}/libpthreadcond.so" >> glibc.filelist -%endif +echo '%{_libdir}/libmemusage.so' >> glibc.filelist +echo '%{_libdir}/libpcprofile.so' >> glibc.filelist ############################################################################## # glibc "common" sub-package ############################################################################## grep '%{_prefix}/bin' master.filelist > common.filelist grep '%{_prefix}/sbin' master.filelist \ - | grep -v '%{_prefix}/sbin/iconvconfig' \ - | grep -v 'nscd' >> common.filelist + | grep -v '%{_prefix}/sbin/iconvconfig' >> common.filelist grep '%{_prefix}/share' master.filelist \ | grep -v \ @@ -726,7 +842,7 @@ grep '%{_prefix}/share' master.filelist \ # glibc "devel" sub-package ############################################################################### %if %{with docs} -grep '%{_infodir}' master.filelist | grep -v '%{_infodir}/dir' > devel.filelist +grep '%{_infodir}' master.filelist | grep -v '%{_infodir}/dir' > help.filelist %endif grep '%{_libdir}/lib.*\.a' master.filelist \ @@ -736,10 +852,7 @@ grep '%{_libdir}/lib.*\.a' master.filelist \ grep '%{_libdir}/.*\.o' < master.filelist >> devel.filelist grep '%{_libdir}/lib.*\.so' < master.filelist >> devel.filelist -sed -i -e '\,libmemusage.so,d' \ - -e '\,libpcprofile.so,d' \ - -e '\,/libnss_[a-z]*\.so$,d' \ - devel.filelist +sed -i -e '\,/libnss_[a-z]*\.so$,d' devel.filelist grep '%{_prefix}/include' < master.filelist >> devel.filelist @@ -748,11 +861,6 @@ grep '%{_libdir}/lib.*\.a' < master.filelist \ >> devel.filelist -############################################################################## -# glibc "nscd" sub-package -############################################################################## -echo '%{_prefix}/sbin/nscd' > nscd.filelist - ############################################################################## # nss modules sub-package ############################################################################## @@ -801,55 +909,84 @@ echo "%{_prefix}/libexec/glibc-benchtests/import_bench.py*" >> benchtests.fileli echo "%{_prefix}/libexec/glibc-benchtests/validate_benchout.py*" >> benchtests.filelist %endif -%if 0%{?_enable_debug_packages} +%if %{with compat_2_17} ############################################################################## -# glibc debuginfo sub-package +# glibc compat-2.17 sub-package ############################################################################## -touch debuginfo_additional.filelist -find_debuginfo_args='--strict-build-id -i' -%ifarch %{x86_arches} -find_debuginfo_args="$find_debuginfo_args \ - -l common.filelist \ - -l debugutils.filelist \ - -l nscd.filelist \ - -p '.*/(sbin|libexec)/.*' \ - -o debuginfo_additional.filelist \ - -l nss_modules.filelist \ - -l libnsl.filelist \ - -l glibc.filelist \ -%if %{with benchtests} - -l benchtests.filelist -%endif - " + echo "%{_libdir}/libpthread-2.17.so" >> compat-2.17.filelist %endif -/usr/lib/rpm/find-debuginfo.sh $find_debuginfo_args -o debuginfo.filelist +reliantlib="" -%ifarch %{x86_arches} -sed -i '\#^$RPM_BUILD_ROOT%{_prefix}/src/debug/#d' debuginfo_additional.filelist -cat debuginfo_additional.filelist >> debuginfo.filelist -find $RPM_BUILD_ROOT%{_prefix}/src/debug \ - \( -type d -printf '%%%%dir ' \) , \ - -printf '%{_prefix}/src/debug/%%P\n' >> debuginfo.filelist - -add_dir=%{_prefix}/lib/debug%{_libdir} -find $RPM_BUILD_ROOT$add_dir -name "*.a" -printf "$add_dir/%%P\n" >> debuginfo.filelist -%endif # %{x86_arches} - -remove_dir="%{_prefix}/src/debug" -remove_dir="$remove_dir $(echo %{_prefix}/lib/debug{,/%{_lib},/bin,/sbin})" -remove_dir="$remove_dir $(echo %{_prefix}/lib/debug%{_prefix}{,/%{_lib},/libexec,/bin,/sbin})" - -for d in $(echo $remove_dir | sed 's/ /\n/g'); do - sed -i "\|^%%dir $d/\?$|d" debuginfo.filelist +function findReliantLib() +{ + local library=$1 + reliantlib=$(readelf -d $library | grep "(NEEDED)" | awk -F "Shared library" '{print $2}')$reliantlib +} + +# remove gconv rpath/runpath +function removeLoadPath() +{ + local file=$1 + local rpathInfo=$(chrpath -l $file | grep "RPATH=") + local runpathInfo=$(chrpath -l $file | grep "RUNPATH=") + + local currPath="" + if [ x"$rpathInfo" != x"" ]; then + currPath=$(echo $rpathInfo | awk -F "RPATH=" '{print $2}') + fi + + if [ x"$runpathInfo" != x"" ]; then + currPath=$(echo $runpathInfo | awk -F "RUNPATH=" '{print $2}') + fi + + if [ x"$currPath" == x"\$ORIGIN" ]; then + chrpath -d $file + + findReliantLib $file + fi +} + +set +e + +# find and remove RPATH/RUNPATH +for file in $(find $RPM_BUILD_ROOT%{_libdir}/gconv/ -name "*.so" -exec file {} ';' | grep "\" | awk -F ':' '{print $1}') +do + removeLoadPath $file done -%endif # 0%{?_enable_debug_packages} +function createSoftLink() +{ + # pick up the dynamic libraries and create softlink for them + local tmplib=$(echo $reliantlib | sed 's/://g' | sed 's/ //g' | sed 's/\[//g' | sed 's/]/\n/g' | sort | uniq) + + for temp in $tmplib + do + if [ -f "$RPM_BUILD_ROOT%{_libdir}/gconv/$temp" ]; then + ln -sf %{_libdir}/gconv/$temp $RPM_BUILD_ROOT%{_libdir}/$temp + echo %{_libdir}/$temp >> glibc.filelist + fi + done +} + +# create soft link for the reliant libraries +createSoftLink +set -e + ############################################################################## # Run the glibc testsuite ############################################################################## %check %if %{with testsuite} + +omit_testsuite() { + while read testsuite; do + testsuite_escape=$(echo "$testsuite" | \ + sed 's/\([.+?^$\/\\|()\[]\|\]\)/\\\0/g') + sed -i "/${testsuite_escape}/d" rpmbuild.tests.sum.not-passing + done +} + # Increase timeouts export TIMEOUTFACTOR=16 parent=$$ @@ -858,14 +995,25 @@ echo ====================TESTING========================= # Default libraries. pushd build-%{target} make %{?_smp_mflags} -O check |& tee rpmbuild.check.log >&2 -test -n tests.sum +test -s tests.sum + +# This hides a test suite build failure, which should be fatal. We +# check "Summary of test results:" below to verify that all tests +# were built and run. if ! grep -q '^Summary of test results:$' rpmbuild.check.log ; then echo "FAIL: test suite build of target: $(basename "$(pwd)")" >& 2 exit 1 fi +grep -v ^PASS: tests.sum | grep -v ^UNSUPPORTED > rpmbuild.tests.sum.not-passing || true + +# Delete the testsuite from the whitelist +cat %{SOURCE8} | \ + grep -v "^$\|^#" | \ + awk -F':' '{if($2 == "" || $2 ~ /'%{_target_cpu}'/ ) {print $1}}' |\ + omit_testsuite + set +x -grep -v ^PASS: tests.sum > rpmbuild.tests.sum.not-passing || true -if test -n rpmbuild.tests.sum.not-passing ; then +if test -s rpmbuild.tests.sum.not-passing ; then echo ===================FAILED TESTS===================== >&2 echo "Target: $(basename "$(pwd)")" >& 2 cat rpmbuild.tests.sum.not-passing >&2 @@ -879,6 +1027,9 @@ if test -n rpmbuild.tests.sum.not-passing ; then fi done done /dev/null || echo "null"` +update_stat=`stat --format="%D %i" "$update_path" || echo "null"` +# When the hard link does not match, use locale-archive.update +if [ "$archive_stat" != "null" ] && + [ "$update_stat" != "null" ] && + [ "$archive_stat" != "$update_stat" ];then + unlink $archive_path + archive_stat="null" +fi +# Regenerate a file if it does not exist +if [ "$archive_stat" == "null" ];then + ln "$update_path" "$archive_path" +fi +# Delete the .rpmsave +if [ -f "$save_path" ];then + unlink $save_path +fi + %pre devel # this used to be a link and it is causing nightmares now if [ -L %{_prefix}/include/scsi ] ; then rm -f %{_prefix}/include/scsi fi -%pre -n nscd -getent group nscd >/dev/null || /usr/sbin/groupadd -g 28 -r nscd -getent passwd nscd >/dev/null || - /usr/sbin/useradd -M -o -r -d / -s /sbin/nologin \ - -c "NSCD Daemon" -u 28 -g nscd nscd - -%post -n nscd -%systemd_post nscd.service - -%preun -n nscd -%systemd_preun nscd.service - -%postun -n nscd -if test $1 = 0; then - /usr/sbin/userdel nscd > /dev/null 2>&1 || : -fi -%systemd_postun_with_restart nscd.service - ############################################################################## # Files list ############################################################################## @@ -1087,23 +1242,23 @@ fi %license COPYING COPYING.LIB LICENSES %files -f common.filelist common -%attr(0644,root,root) %verify(not md5 size mtime mode) %ghost %config(missingok,noreplace) %{_prefix}/lib/locale/locale-archive %dir %{_prefix}/lib/locale %dir %{_prefix}/lib/locale/C.utf8 %{_prefix}/lib/locale/C.utf8/* -%{_prefix}/lib/locale/zh_CN.utf8 -%{_prefix}/lib/locale/en_US.utf8 -%{_prefix}/share/locale/zh_CN -%{_prefix}/share/locale/en_GB +%{_prefix}/lib/locale/zh* +%{_prefix}/lib/locale/en* +%{_prefix}/share/locale/zh* +%{_prefix}/share/locale/en* %files -f libc.lang all-langpacks %{_prefix}/lib/locale %exclude %{_prefix}/lib/locale/locale-archive +%exclude %{_prefix}/lib/locale/locale-archive.update %exclude %{_prefix}/lib/locale/C.utf8 -%exclude %{_prefix}/lib/locale/zh_CN.utf8 -%exclude %{_prefix}/lib/locale/en_US.utf8 -%exclude %{_prefix}/share/locale/zh_CN -%exclude %{_prefix}/share/locale/en_GB +%exclude %{_prefix}/lib/locale/zh* +%exclude %{_prefix}/lib/locale/en* +%exclude %{_prefix}/share/locale/zh* +%exclude %{_prefix}/share/locale/en* %files locale-source %dir %{_prefix}/share/i18n/locales @@ -1111,26 +1266,11 @@ fi %dir %{_prefix}/share/i18n/charmaps %{_prefix}/share/i18n/charmaps/* -%files -f devel.filelist devel +%files locale-archive +%attr(0644,root,root) %{_prefix}/lib/locale/locale-archive +%attr(0644,root,root) %{_prefix}/lib/locale/locale-archive.update -%files -f nscd.filelist -n nscd -%config(noreplace) /etc/nscd.conf -%dir %attr(0755,root,root) /var/run/nscd -%dir %attr(0755,root,root) /var/db/nscd -/lib/systemd/system/nscd.service -/lib/systemd/system/nscd.socket -%{_tmpfilesdir}/nscd.conf -%attr(0644,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/run/nscd/nscd.pid -%attr(0666,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/run/nscd/socket -%attr(0600,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/run/nscd/passwd -%attr(0600,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/run/nscd/group -%attr(0600,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/run/nscd/hosts -%attr(0600,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/run/nscd/services -%attr(0600,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/db/nscd/passwd -%attr(0600,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/db/nscd/group -%attr(0600,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/db/nscd/hosts -%attr(0600,root,root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/db/nscd/services -%ghost %config(missingok,noreplace) /etc/sysconfig/nscd +%files -f devel.filelist devel %files -f nss_modules.filelist -n nss_modules /var/db/Makefile @@ -1146,14 +1286,7 @@ fi %files -f benchtests.filelist benchtests %endif -%if 0%{?_enable_debug_packages} -%files -f debuginfo.filelist debuginfo - -%files debugsource -%endif - - -%files help +%files -f help.filelist help #Doc of glibc package %doc README NEWS INSTALL elf/rtld-debugger-interface.txt #Doc of common sub-package @@ -1162,7 +1295,286 @@ fi #Doc of nss_modules sub-package %doc hesiod/README.hesiod +%if %{with compat_2_17} +%files -f compat-2.17.filelist compat-2.17 +%endif + %changelog +* Tue Mar 29 2022 Yang Yanchao - 2.34-71 +- mv libc.info.gz* to the package glibc-help + +* Tue Mar 15 2022 Yang Yanchao - 2.34-70 +- malloc: Add madvise support for Transparent Huge Pages +- malloc: Add THP/madvise support for sbrk +- malloc: Move mmap logic to its own function +- malloc: Add Huge Page support for mmap +- malloc: Add Huge Page support to arenas +- malloc: Move MORECORE fallback mmap to sysmalloc_mmap_fallback +- malloc: Enable huge page support on main arena + +* Sat Mar 12 2022 Yang Yanchao - 2.34-69 +- malloc: use __get_nprocs replace __get_nprocs_sched. + +* Sat Mar 5 2022 zhoukang - 2.34-68 +- add dynamic linker load lib use hugepage + +* Thu Mar 3 2022 qinyu - 2.34-67 +- disable rseq by default with tunable + +* Thu Mar 3 2022 Yunfeng Ye - 2.34-66 +- add PTRACE_GET_RSEQ_CONFIGURATION + +* Thu Mar 3 2022 Qingqing Li - 2.34-65 +- add chrpath to BuildRequires to make + 'remove shared library's RPATH/RUNPATH' to take effect + +* Wed Mar 2 2022 Qingqing Li - 2.34-64 +- x86: strncmp-avx2-rtm and wcsncmp-avx2-rtm fallback on + non-rtm variants when avoiding overflow. [BZ #28896] + +* Tue Mar 1 2022 Yang Yanchao - 2.34-63 +- Merge testsuite_whitelist.aarch64 and testsuite_whitelist.x86_64 to testsuite_whitelist. + +* Tue Mar 1 2022 Qingqing Li - 2.34-62 +- remove shared library's RPATH/RUNPATH for security + +* Fri Feb 25 2022 qinyu - 2.34-61 +- add rseq support + +* Thu Feb 24 2022 Yang Yanchao - 2.34-60 +- Only in the CI environment, the build is interrupted due to test case failure. + +* Wed Feb 23 2022 Yang Yanchao - 2.34-59 +- strcmp: delete align for loop_aligned + +* Wed Feb 23 2022 Yang Yanchao - 2.34-58 +- The release of glibc.src.rpm in OpenEuler is not based on the architecture. + Developers only have glibc.src.rpm in the ARM, so add all testsuite_whitelist in glibc.src.rpm. + +* Tue Feb 22 2022 Qingqing Li - 2.34-57 +- tzselect: use region to instead of country for extract timezone selection. + +* Thu Feb 10 2022 jiangheng - 2.34-56 +- remove nscd; the functionality nscd currently provides can be + achieved by using systemd-resolved for DNS caching and the sssd + daemon for everything else + +* Wed Feb 9 2022 Qingqing Li - 2.34-55 +- linux: fix accurarcy of get_nprocs and get_nprocs_conf [BZ #28865] + +* Tue Feb 8 2022 Yang Yanchao - 2.34-54 +- disable rt/tst-cpuclock2 which often fails in CI. + +* Tue Feb 8 2022 Qingqing Li - 2.34-53 +- elf: fix glibc 2.34 ABI omission +- x86: black list more intel cpus for TSX [BZ #27398] +- recvmsg/recvmmsg: fix ancillary 64-bit time timestamp comversion [BZ #28349, BZ #28350] +- socket: do not use AF_NETLINK in __opensock + +* Mon Feb 7 2022 Qingqing Li - 2.34-52 +- fix misc/tst-glibcsyscalls failed due to kernel reserve some syscalls + +* Mon Feb 7 2022 Qingqing Li - 2.34-51 +- Pass the actual number of bytes returned by the kernel. + Fixes: 33099d72e41c ("linux: Simplify get_nprocs") + +* Fri Jan 28 2022 Yang Yanchao - 2.34-50 +- The default debuginfo management mechanism is deleted. + Instead, Use the default macro of RPM. + There are two changes: + 1. The source files in /usr/src are + correctly packed into the glibc-debugsource. + 2. The debugging file contains the glibc version number. + +* Fri Jan 28 2022 Lv Ying - 2.34-49 +- fix CVE-2019-1010023 + +* Fri Jan 28 2022 Qingqing Li - 2.34-48 +- Fix __wcsncmp_evex in strcmp-evex.S [BZ #28755] +- Fix __wcsncmp_avx2 in strcmp-avx2.S [BZ #28755] + +* Tue Jan 25 2022 Chuang Fang - 2.34-47 +- Disable debuginfod in printer tests [BZ #28757] +- i386: Remove broken CAN_USE_REGISTER_ASM_EBP (bug 28771) +- x86: use default cache size if it cannot be determined [BZ #28784] + +* Tue Jan 25 2022 Qingqing Li - 2.34-46 +- fix CVE-2021-3998 and CVE-2021-3999 + +* Fri Jan 21 2022 Yang Yanchao - 2.34-45 +- disable check-installed-headers-c and check-installed-headers-cxx + and delete glibc-benchtest to improve build speed + +* Fri Jan 21 2022 Qingqing Li - 2.34-44 +- support: Add check for TID zero in support_wait_for_thread_exit + +* Tue Jan 18 2022 Qingqing Li - 2.34-43 +- fix CVE-2022-23218 and CVE-2022-23219 + +* Tue Jan 11 2022 Yang Yanchao - 2.34-42 +- delete macro __filter_GLIBC_PRIVATE which is not support in rpm-4.17 + Use arbitrary filtering to control GLIBC_PRIVATE + +* Mon Jan 10 2022 Qingqing Li - 2.34-41 +- timex: Use 64-bit fields on 32-bit TIMESIZE=64 systems. BZ #28469 +- malloc: Handle NULL input to malloc usable size. BZ #28506 +- elf: Earlier missing dynamic segment check in _dl_map_object_from_fd +- nptl: Do not set signal mask on second setjmp return. BZ #28607 +- linux: use /proc/stat fallback for __get_nprocs_conf. BZ #28624 +- nss: Use "file dns" as the default for the hosts database. BZ #28700 +- int/plural.y: Avoid conflicting declarations of yyerror and yylex +- aarch64: Check for SVE in ifuncs BZ #28744 +- Fix subscript error with odd TZif file BZ #28338 +- timezone: handle truncated timezones from tzcode 2021 +- timezone: test case for BZ #28707 + +* Mon Jan 10 2022 Yang Yanchao - 2.34-40 +- rpm-build move find-debuginfo.sh into debugedit. + and change the path from "/usr/lib/rpm" to "/usr/bin" + adapts this change + +* Tue Dec 28 2021 Qingqing Li - 2.34-39 +- support: Also return fd when it is 0. + +* Mon Dec 27 2021 Qingqing Li - 2.34-38 +- elf: replace nsid with args.nsid [BZ #27609] + +* Sat Dec 25 2021 liusirui - 2.34-37 +- ld.so: Don't fill the DT_DEBUG entry in ld.so [BZ #28129] + +* Fri Dec 24 2021 Qingqing Li - 2.34-36 +- do not define tgmath.h fmaxmag, fminmag macros for C2X (BZ #28397) + +* Fri Dec 24 2021 Qingqing Li - 2.34-35 +- io: Fix ftw internal realloc buffer (BZ #28126) + +* Tue Dec 21 2021 Qingqing Li - 2.34-34 +- tst: fix failing nss/tst-nss-files-hosts-long with local resolver + use support_open_dev_null_range io/tst-closefrom, mise/tst-close_range, and posix/tst-spawn5(BZ#28260) + nptl: add one more barrier to nptl/tst-create1 + +* Wed Dec 15 2021 Qingqing Li - 2.34-33 +- pthread/tst-cancel28: Fix barrier re-init race condition + +* Thu Dec 9 2021 Yang Yanchao - 2.34-32 +- Deleted some unnecessary command when make master.filelist + +* Thu Dec 9 2021 Yang Yanchao - 2.34-31 +- support all Chinese and English by default + add zh_* and en_* to glibc-common + the size of glibc-common is increased from 1.8MB to 3.5MB + +* Fri Dec 3 2021 Yang Yanchao - 2.34-30 +- turn the default value of x86_rep_stosb_threshold from 2k to 1M + +* Thu Dec 2 2021 Qingqing Li - 2.34-29 +- revert the use of sched_getaffinity [BZ #28310] + +* Tue Nov 30 2021 Bin Wang - 2.34-28 +- Linux: Simplify __opensock and fix race condition [BZ #28353] + +* Wed Nov 24 2021 Yang Yanchao - 2.34-27 +- Refactor the libpthread-2.17.so code and pass all test cases. + delete libpthread-2.17.so from glibc-devel + +* Fri Nov 19 2021 Qingqing Li - 2.34-26 +- revert supress -Wcast-qual warnings in bsearch + +* Mon Nov 15 2021 Qingqing Li - 2.34-25 +- fix attribute access mode on getcwd [BZ #27476] +- supress -Wcast-qual warnings in bsearch + +* Mon Nov 15 2021 Qingqing Li - 2.34-24 +- elf: fix ld.so crash while loading a DSO with a read-only dynamic section + https://sourceware.org/bugzilla/show_bug.cgi?id=28340 + +* Wed Nov 10 2021 Qingqing Li - 2.34-23 +- gconv: Do not emit spurious NUL character in ISO-2022-JP-3, + this also fix CVE-2021-43396. + uplink: https://sourceware.org/bugzilla/show_bug.cgi?id=28524 + +* Tue Nov 9 2021 Qingqing Li - 2.34-22 +- iconvconfig: Fix behaviour with --prefix + uplink: https://sourceware.org/bugzilla/show_bug.cgi?id=28199 + +* Mon Nov 8 2021 Qingqing Li - 2.34-21 +- nptl: pthread_kill race condition issues fixed. + uplink: https://sourceware.org/bugzilla/show_bug.cgi?id=19193 + https://sourceware.org/bugzilla/show_bug.cgi?id=12889 + https://sourceware.org/bugzilla/show_bug.cgi?id=28036 + https://sourceware.org/bugzilla/show_bug.cgi?id=28363 + https://sourceware.org/bugzilla/show_bug.cgi?id=28407 + +* Thu Nov 4 2021 Qingqing Li - 2.34-20 +- nptl: pthread_kill and pthread_cancel return success + for satisfy posix standard. + uplink: https://sourceware.org/bugzilla/show_bug.cgi?id=19193 + +* Fri Oct 29 2021 Qingqing Li - 2.34-19 +- aarch64: update a64fx memset not to degrade at 16KB + +* Thu Oct 28 2021 Qingqing Li - 2.34-18 +- use testl instead of andl to check __x86_string_control to + avoid updating __x86_string_control + +* Tue Oct 26 2021 Yang Yanchao - 2.34-17 +- Show more debugging information during testsuite + +* Tue Oct 26 2021 Chuangchuang Fang - 2.34-16 +- Use __executable_start as the lowest address for profiling + +* Tue Oct 26 2021 Yang Yanchao - 2.34-15 +- add glibc-compat-2.17 subpackage to provide the function of + the glibc-2.17 pthread library. + Currently, provide pthread_condition function. + +* Mon Oct 25 2021 Qingqing Li - 2.34-14 +- mtrace fix output with PIE and ASLR. +- elf: rtld copy terminating null in tunables strdup. + +* Mon Oct 25 2021 Qingqing Li - 2.34-13 +- fpu: x86-64 optimize load of all bits set into ZMM register. + +* Tue Oct 19 2021 Yang Yanchao - 2.34-12 +- Add locale-archive sub packages to support more languages + and reduce memory usage. + +* Tue Oct 12 2021 Yang Yanchao - 2.34-11 +- Add the testsuite whitelist. + If a test case out of the trustlist fails, the compilation is interrupted. + +* Mon Oct 11 2021 Qingqing Li - 2.34-10 +- update test memmove.c to cover 16KB. + +* Wed Sep 29 2021 Qingqing Li - 2.34-9 +- elf: drop elf/tls-macros.h in favor of thread tls_mode attribute. +- use __ehdr_start for __GLOBAL_OFFSET_TABLE[0] + +* Wed Sep 29 2021 Qingqing Li - 2.34-8 +- fix overflow ittimer tests on 32 bit system + +* Mon Sep 27 2021 Qingqing Li - 2.34-7 +- mtrace: use a static buffer for printing, fix memory leak. + upstream link: https://sourceware.org/bugzilla/show_bug.cgi?id=25947 + +* Sun Sep 26 2021 Qingqing Li - 2.34-6 +- elf: Unconditionally use __ehdr_start. +- aarch64: Make elf_machine_{load_addr,dynamic} robust [BZ #28203]. + upstream link: https://sourceware.org/bugzilla/show_bug.cgi?id=28203 + +* Fri Sep 17 2021 Qingqing Li - 2.34-5 +- aarch64: optimize memset performance. + +* Fri Sep 17 2021 Qingqing Li - 2.34-4 +- backport upstream patches to fix some memory leak and double free bugs + +* Tue Sep 14 2021 Yang Yanchao - 2.34-3 +- add --enable-static-pie in aarch64 + +* Wed Aug 25 2021 Qingqing Li - 2.34-2 +- fix CVE-2021-38604 + https://sourceware.org/bugzilla/show_bug.cgi?id=28213 + * Thu Aug 5 2021 Qingqing Li - 2.34-1 - upgrade to 2.34. diff --git a/i386-Remove-broken-CAN_USE_REGISTER_ASM_EBP-bug-2877.patch b/i386-Remove-broken-CAN_USE_REGISTER_ASM_EBP-bug-2877.patch new file mode 100644 index 0000000000000000000000000000000000000000..181b1777d152fd85ffdd04a3c7b03616bf8f92a9 --- /dev/null +++ b/i386-Remove-broken-CAN_USE_REGISTER_ASM_EBP-bug-2877.patch @@ -0,0 +1,463 @@ +From 2fe2af88abd13ae5636881da2e26f461ecb7dfb5 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Thu, 13 Jan 2022 14:59:29 +0100 +Subject: [PATCH] i386: Remove broken CAN_USE_REGISTER_ASM_EBP (bug 28771) + +The configure check for CAN_USE_REGISTER_ASM_EBP tried to compile a +simple function that uses %ebp as an inline assembly operand. If +compilation failed, CAN_USE_REGISTER_ASM_EBP was set 0, which +eventually had these consequences: + +(1) %ebx was avoided as an inline assembly operand, with an + assembler macro hack to avoid unnecessary register moves. +(2) %ebp was avoided as an inline assembly operand, using an + out-of-line syscall function for 6-argument system calls. + +(1) is no longer needed for any GCC version that is supported for +building glibc. %ebx can be used directly as a register operand. +Therefore, this commit removes the %ebx avoidance completely. This +avoids the assembler macro hack, which turns out to be incompatible +with the current Systemtap probe macros (which switch to .altmacro +unconditionally). + +(2) is still needed in many build configurations. The existing +configure check cannot really capture that because the simple function +succeeds to compile, while the full glibc build still fails. +Therefore, this commit removes the check, the CAN_USE_REGISTER_ASM_EBP +macro, and uses the out-of-line syscall function for 6-argument system +calls unconditionally. + +Reviewed-by: H.J. Lu +(cherry picked from commit a78e6a10d0b50d0ca80309775980fc99944b1727) +--- + NEWS | 1 + + config.h.in | 4 - + sysdeps/unix/sysv/linux/i386/configure | 39 ---- + sysdeps/unix/sysv/linux/i386/configure.ac | 17 -- + sysdeps/unix/sysv/linux/i386/sysdep.h | 222 +++------------------- + 5 files changed, 28 insertions(+), 255 deletions(-) + +diff --git a/NEWS b/NEWS +index 5c253a4392..759a80b1b5 100644 +--- a/NEWS ++++ b/NEWS +@@ -30,6 +30,7 @@ The following bugs are resolved with this release: + AMD64 cpus + [28091] network: ns_name_skip may return 0 for domain names without + terminator ++ [28771] %ebx optimization macros are incompatible with .altmacro + + + Version 2.33 +diff --git a/config.h.in b/config.h.in +index 8b45a3a61d..37207df94f 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -283,10 +283,6 @@ + /* Define if static PIE is enabled. */ + #define ENABLE_STATIC_PIE 0 + +-/* Some compiler options may now allow to use ebp in __asm__ (used mainly +- in i386 6 argument syscall issue). */ +-#define CAN_USE_REGISTER_ASM_EBP 0 +- + /* The default value of x86 CET control. */ + #define DEFAULT_DL_X86_CET_CONTROL cet_elf_property + +diff --git a/sysdeps/unix/sysv/linux/i386/configure b/sysdeps/unix/sysv/linux/i386/configure +index 0327590486..f119e62fc3 100644 +--- a/sysdeps/unix/sysv/linux/i386/configure ++++ b/sysdeps/unix/sysv/linux/i386/configure +@@ -1,44 +1,5 @@ + # This file is generated from configure.ac by Autoconf. DO NOT EDIT! + # Local configure fragment for sysdeps/unix/sysv/linux/i386. + +-# Check if CFLAGS allows compiler to use ebp register in inline assembly. +- +-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler flags allows ebp in inline assembly" >&5 +-$as_echo_n "checking if compiler flags allows ebp in inline assembly... " >&6; } +-if ${libc_cv_can_use_register_asm_ebp+:} false; then : +- $as_echo_n "(cached) " >&6 +-else +- +-cat confdefs.h - <<_ACEOF >conftest.$ac_ext +-/* end confdefs.h. */ +- +- void foo (int i) +- { +- register int reg asm ("ebp") = i; +- asm ("# %0" : : "r" (reg)); +- } +-int +-main () +-{ +- +- ; +- return 0; +-} +-_ACEOF +-if ac_fn_c_try_compile "$LINENO"; then : +- libc_cv_can_use_register_asm_ebp=yes +-else +- libc_cv_can_use_register_asm_ebp=no +-fi +-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +- +-fi +-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_can_use_register_asm_ebp" >&5 +-$as_echo "$libc_cv_can_use_register_asm_ebp" >&6; } +-if test $libc_cv_can_use_register_asm_ebp = yes; then +- $as_echo "#define CAN_USE_REGISTER_ASM_EBP 1" >>confdefs.h +- +-fi +- + libc_cv_gcc_unwind_find_fde=yes + ldd_rewrite_script=sysdeps/unix/sysv/linux/ldd-rewrite.sed +diff --git a/sysdeps/unix/sysv/linux/i386/configure.ac b/sysdeps/unix/sysv/linux/i386/configure.ac +index 9e980784bb..64ab2cc2c8 100644 +--- a/sysdeps/unix/sysv/linux/i386/configure.ac ++++ b/sysdeps/unix/sysv/linux/i386/configure.ac +@@ -1,22 +1,5 @@ + GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory. + # Local configure fragment for sysdeps/unix/sysv/linux/i386. + +-# Check if CFLAGS allows compiler to use ebp register in inline assembly. +-AC_CACHE_CHECK([if compiler flags allows ebp in inline assembly], +- libc_cv_can_use_register_asm_ebp, [ +-AC_COMPILE_IFELSE( +- [AC_LANG_PROGRAM([ +- void foo (int i) +- { +- register int reg asm ("ebp") = i; +- asm ("# %0" : : "r" (reg)); +- }])], +- [libc_cv_can_use_register_asm_ebp=yes], +- [libc_cv_can_use_register_asm_ebp=no]) +-]) +-if test $libc_cv_can_use_register_asm_ebp = yes; then +- AC_DEFINE(CAN_USE_REGISTER_ASM_EBP) +-fi +- + libc_cv_gcc_unwind_find_fde=yes + ldd_rewrite_script=sysdeps/unix/sysv/linux/ldd-rewrite.sed +diff --git a/sysdeps/unix/sysv/linux/i386/sysdep.h b/sysdeps/unix/sysv/linux/i386/sysdep.h +index 8a9911b7ac..39d6a3c134 100644 +--- a/sysdeps/unix/sysv/linux/i386/sysdep.h ++++ b/sysdeps/unix/sysv/linux/i386/sysdep.h +@@ -43,15 +43,6 @@ + # endif + #endif + +-/* Since GCC 5 and above can properly spill %ebx with PIC when needed, +- we can inline syscalls with 6 arguments if GCC 5 or above is used +- to compile glibc. Disable GCC 5 optimization when compiling for +- profiling or when -fno-omit-frame-pointer is used since asm ("ebp") +- can't be used to put the 6th argument in %ebp for syscall. */ +-#if !defined PROF && CAN_USE_REGISTER_ASM_EBP +-# define OPTIMIZE_FOR_GCC_5 +-#endif +- + #ifdef __ASSEMBLER__ + + /* Linux uses a negative return value to indicate syscall errors, +@@ -239,36 +230,6 @@ + extern int __syscall_error (int) + attribute_hidden __attribute__ ((__regparm__ (1))); + +-#ifndef OPTIMIZE_FOR_GCC_5 +-/* We need some help from the assembler to generate optimal code. We +- define some macros here which later will be used. */ +-asm (".L__X'%ebx = 1\n\t" +- ".L__X'%ecx = 2\n\t" +- ".L__X'%edx = 2\n\t" +- ".L__X'%eax = 3\n\t" +- ".L__X'%esi = 3\n\t" +- ".L__X'%edi = 3\n\t" +- ".L__X'%ebp = 3\n\t" +- ".L__X'%esp = 3\n\t" +- ".macro bpushl name reg\n\t" +- ".if 1 - \\name\n\t" +- ".if 2 - \\name\n\t" +- "error\n\t" +- ".else\n\t" +- "xchgl \\reg, %ebx\n\t" +- ".endif\n\t" +- ".endif\n\t" +- ".endm\n\t" +- ".macro bpopl name reg\n\t" +- ".if 1 - \\name\n\t" +- ".if 2 - \\name\n\t" +- "error\n\t" +- ".else\n\t" +- "xchgl \\reg, %ebx\n\t" +- ".endif\n\t" +- ".endif\n\t" +- ".endm\n\t"); +- + /* Six-argument syscalls use an out-of-line helper, because an inline + asm using all registers apart from %esp cannot work reliably and + the assembler does not support describing an asm that saves and +@@ -279,7 +240,6 @@ struct libc_do_syscall_args + { + int ebx, edi, ebp; + }; +-#endif + + # define VDSO_NAME "LINUX_2.6" + # define VDSO_HASH 61765110 +@@ -332,14 +292,8 @@ struct libc_do_syscall_args + + /* Each object using 6-argument inline syscalls must include a + definition of __libc_do_syscall. */ +-#ifdef OPTIMIZE_FOR_GCC_5 +-# define INTERNAL_SYSCALL_MAIN_6(name, args...) \ +- INTERNAL_SYSCALL_MAIN_INLINE(name, 6, args) +-# define INTERNAL_SYSCALL_MAIN_NCS_6(name, args...) \ +- INTERNAL_SYSCALL_MAIN_NCS(name, 6, args) +-#else /* GCC 5 */ +-# define INTERNAL_SYSCALL_MAIN_6(name, arg1, arg2, arg3, \ +- arg4, arg5, arg6) \ ++#define INTERNAL_SYSCALL_MAIN_6(name, arg1, arg2, arg3, \ ++ arg4, arg5, arg6) \ + struct libc_do_syscall_args _xv = \ + { \ + (int) (arg1), \ +@@ -352,8 +306,8 @@ struct libc_do_syscall_args + : "=a" (resultvar) \ + : "i" (__NR_##name), "c" (arg2), "d" (arg3), "S" (arg4), "D" (&_xv) \ + : "memory", "cc") +-# define INTERNAL_SYSCALL_MAIN_NCS_6(name, arg1, arg2, arg3, \ +- arg4, arg5, arg6) \ ++#define INTERNAL_SYSCALL_MAIN_NCS_6(name, arg1, arg2, arg3, \ ++ arg4, arg5, arg6) \ + struct libc_do_syscall_args _xv = \ + { \ + (int) (arg1), \ +@@ -366,7 +320,6 @@ struct libc_do_syscall_args + : "=a" (resultvar) \ + : "a" (name), "c" (arg2), "d" (arg3), "S" (arg4), "D" (&_xv) \ + : "memory", "cc") +-#endif /* GCC 5 */ + + #define INTERNAL_SYSCALL(name, nr, args...) \ + ({ \ +@@ -380,193 +333,72 @@ struct libc_do_syscall_args + (int) resultvar; }) + + #if I386_USE_SYSENTER +-# ifdef OPTIMIZE_FOR_GCC_5 +-# ifdef PIC +-# define INTERNAL_SYSCALL_MAIN_INLINE(name, nr, args...) \ ++# ifdef PIC ++# define INTERNAL_SYSCALL_MAIN_INLINE(name, nr, args...) \ + LOADREGS_##nr(args) \ + asm volatile ( \ + "call *%%gs:%P2" \ + : "=a" (resultvar) \ + : "a" (__NR_##name), "i" (offsetof (tcbhead_t, sysinfo)) \ + ASMARGS_##nr(args) : "memory", "cc") +-# define INTERNAL_SYSCALL_MAIN_NCS(name, nr, args...) \ ++# define INTERNAL_SYSCALL_MAIN_NCS(name, nr, args...) \ + LOADREGS_##nr(args) \ + asm volatile ( \ + "call *%%gs:%P2" \ + : "=a" (resultvar) \ + : "a" (name), "i" (offsetof (tcbhead_t, sysinfo)) \ + ASMARGS_##nr(args) : "memory", "cc") +-# else +-# define INTERNAL_SYSCALL_MAIN_INLINE(name, nr, args...) \ ++# else /* I386_USE_SYSENTER && !PIC */ ++# define INTERNAL_SYSCALL_MAIN_INLINE(name, nr, args...) \ + LOADREGS_##nr(args) \ + asm volatile ( \ + "call *_dl_sysinfo" \ + : "=a" (resultvar) \ + : "a" (__NR_##name) ASMARGS_##nr(args) : "memory", "cc") +-# define INTERNAL_SYSCALL_MAIN_NCS(name, nr, args...) \ ++# define INTERNAL_SYSCALL_MAIN_NCS(name, nr, args...) \ + LOADREGS_##nr(args) \ + asm volatile ( \ + "call *_dl_sysinfo" \ + : "=a" (resultvar) \ + : "a" (name) ASMARGS_##nr(args) : "memory", "cc") +-# endif +-# else /* GCC 5 */ +-# ifdef PIC +-# define INTERNAL_SYSCALL_MAIN_INLINE(name, nr, args...) \ +- EXTRAVAR_##nr \ +- asm volatile ( \ +- LOADARGS_##nr \ +- "movl %1, %%eax\n\t" \ +- "call *%%gs:%P2\n\t" \ +- RESTOREARGS_##nr \ +- : "=a" (resultvar) \ +- : "i" (__NR_##name), "i" (offsetof (tcbhead_t, sysinfo)) \ +- ASMFMT_##nr(args) : "memory", "cc") +-# define INTERNAL_SYSCALL_MAIN_NCS(name, nr, args...) \ +- EXTRAVAR_##nr \ +- asm volatile ( \ +- LOADARGS_##nr \ +- "call *%%gs:%P2\n\t" \ +- RESTOREARGS_##nr \ +- : "=a" (resultvar) \ +- : "0" (name), "i" (offsetof (tcbhead_t, sysinfo)) \ +- ASMFMT_##nr(args) : "memory", "cc") +-# else +-# define INTERNAL_SYSCALL_MAIN_INLINE(name, nr, args...) \ +- EXTRAVAR_##nr \ +- asm volatile ( \ +- LOADARGS_##nr \ +- "movl %1, %%eax\n\t" \ +- "call *_dl_sysinfo\n\t" \ +- RESTOREARGS_##nr \ +- : "=a" (resultvar) \ +- : "i" (__NR_##name) ASMFMT_##nr(args) : "memory", "cc") +-# define INTERNAL_SYSCALL_MAIN_NCS(name, nr, args...) \ +- EXTRAVAR_##nr \ +- asm volatile ( \ +- LOADARGS_##nr \ +- "call *_dl_sysinfo\n\t" \ +- RESTOREARGS_##nr \ +- : "=a" (resultvar) \ +- : "0" (name) ASMFMT_##nr(args) : "memory", "cc") +-# endif +-# endif /* GCC 5 */ +-#else +-# ifdef OPTIMIZE_FOR_GCC_5 +-# define INTERNAL_SYSCALL_MAIN_INLINE(name, nr, args...) \ ++# endif /* I386_USE_SYSENTER && !PIC */ ++#else /* !I386_USE_SYSENTER */ ++# define INTERNAL_SYSCALL_MAIN_INLINE(name, nr, args...) \ + LOADREGS_##nr(args) \ + asm volatile ( \ + "int $0x80" \ + : "=a" (resultvar) \ + : "a" (__NR_##name) ASMARGS_##nr(args) : "memory", "cc") +-# define INTERNAL_SYSCALL_MAIN_NCS(name, nr, args...) \ ++# define INTERNAL_SYSCALL_MAIN_NCS(name, nr, args...) \ + LOADREGS_##nr(args) \ + asm volatile ( \ + "int $0x80" \ + : "=a" (resultvar) \ + : "a" (name) ASMARGS_##nr(args) : "memory", "cc") +-# else /* GCC 5 */ +-# define INTERNAL_SYSCALL_MAIN_INLINE(name, nr, args...) \ +- EXTRAVAR_##nr \ +- asm volatile ( \ +- LOADARGS_##nr \ +- "movl %1, %%eax\n\t" \ +- "int $0x80\n\t" \ +- RESTOREARGS_##nr \ +- : "=a" (resultvar) \ +- : "i" (__NR_##name) ASMFMT_##nr(args) : "memory", "cc") +-# define INTERNAL_SYSCALL_MAIN_NCS(name, nr, args...) \ +- EXTRAVAR_##nr \ +- asm volatile ( \ +- LOADARGS_##nr \ +- "int $0x80\n\t" \ +- RESTOREARGS_##nr \ +- : "=a" (resultvar) \ +- : "0" (name) ASMFMT_##nr(args) : "memory", "cc") +-# endif /* GCC 5 */ +-#endif +- +-#define LOADARGS_0 +-#ifdef __PIC__ +-# if I386_USE_SYSENTER && defined PIC +-# define LOADARGS_1 \ +- "bpushl .L__X'%k3, %k3\n\t" +-# define LOADARGS_5 \ +- "movl %%ebx, %4\n\t" \ +- "movl %3, %%ebx\n\t" +-# else +-# define LOADARGS_1 \ +- "bpushl .L__X'%k2, %k2\n\t" +-# define LOADARGS_5 \ +- "movl %%ebx, %3\n\t" \ +- "movl %2, %%ebx\n\t" +-# endif +-# define LOADARGS_2 LOADARGS_1 +-# define LOADARGS_3 \ +- "xchgl %%ebx, %%edi\n\t" +-# define LOADARGS_4 LOADARGS_3 +-#else +-# define LOADARGS_1 +-# define LOADARGS_2 +-# define LOADARGS_3 +-# define LOADARGS_4 +-# define LOADARGS_5 +-#endif +- +-#define RESTOREARGS_0 +-#ifdef __PIC__ +-# if I386_USE_SYSENTER && defined PIC +-# define RESTOREARGS_1 \ +- "bpopl .L__X'%k3, %k3\n\t" +-# define RESTOREARGS_5 \ +- "movl %4, %%ebx" +-# else +-# define RESTOREARGS_1 \ +- "bpopl .L__X'%k2, %k2\n\t" +-# define RESTOREARGS_5 \ +- "movl %3, %%ebx" +-# endif +-# define RESTOREARGS_2 RESTOREARGS_1 +-# define RESTOREARGS_3 \ +- "xchgl %%edi, %%ebx\n\t" +-# define RESTOREARGS_4 RESTOREARGS_3 +-#else +-# define RESTOREARGS_1 +-# define RESTOREARGS_2 +-# define RESTOREARGS_3 +-# define RESTOREARGS_4 +-# define RESTOREARGS_5 +-#endif ++#endif /* !I386_USE_SYSENTER */ + +-#ifdef OPTIMIZE_FOR_GCC_5 +-# define LOADREGS_0() +-# define ASMARGS_0() +-# define LOADREGS_1(arg1) \ ++#define LOADREGS_0() ++#define ASMARGS_0() ++#define LOADREGS_1(arg1) \ + LOADREGS_0 () +-# define ASMARGS_1(arg1) \ ++#define ASMARGS_1(arg1) \ + ASMARGS_0 (), "b" ((unsigned int) (arg1)) +-# define LOADREGS_2(arg1, arg2) \ ++#define LOADREGS_2(arg1, arg2) \ + LOADREGS_1 (arg1) +-# define ASMARGS_2(arg1, arg2) \ ++#define ASMARGS_2(arg1, arg2) \ + ASMARGS_1 (arg1), "c" ((unsigned int) (arg2)) +-# define LOADREGS_3(arg1, arg2, arg3) \ ++#define LOADREGS_3(arg1, arg2, arg3) \ + LOADREGS_2 (arg1, arg2) +-# define ASMARGS_3(arg1, arg2, arg3) \ ++#define ASMARGS_3(arg1, arg2, arg3) \ + ASMARGS_2 (arg1, arg2), "d" ((unsigned int) (arg3)) +-# define LOADREGS_4(arg1, arg2, arg3, arg4) \ ++#define LOADREGS_4(arg1, arg2, arg3, arg4) \ + LOADREGS_3 (arg1, arg2, arg3) +-# define ASMARGS_4(arg1, arg2, arg3, arg4) \ ++#define ASMARGS_4(arg1, arg2, arg3, arg4) \ + ASMARGS_3 (arg1, arg2, arg3), "S" ((unsigned int) (arg4)) +-# define LOADREGS_5(arg1, arg2, arg3, arg4, arg5) \ ++#define LOADREGS_5(arg1, arg2, arg3, arg4, arg5) \ + LOADREGS_4 (arg1, arg2, arg3, arg4) +-# define ASMARGS_5(arg1, arg2, arg3, arg4, arg5) \ ++#define ASMARGS_5(arg1, arg2, arg3, arg4, arg5) \ + ASMARGS_4 (arg1, arg2, arg3, arg4), "D" ((unsigned int) (arg5)) +-# define LOADREGS_6(arg1, arg2, arg3, arg4, arg5, arg6) \ +- register unsigned int _a6 asm ("ebp") = (unsigned int) (arg6); \ +- LOADREGS_5 (arg1, arg2, arg3, arg4, arg5) +-# define ASMARGS_6(arg1, arg2, arg3, arg4, arg5, arg6) \ +- ASMARGS_5 (arg1, arg2, arg3, arg4, arg5), "r" (_a6) +-#endif /* GCC 5 */ + + #define ASMFMT_0() + #ifdef __PIC__ +-- +2.27.0 + diff --git a/iconv_charmap-Close-output-file-when-done.patch b/iconv_charmap-Close-output-file-when-done.patch new file mode 100644 index 0000000000000000000000000000000000000000..a96692223ccbd7427bc30fa3dcde6250e7b43fc8 --- /dev/null +++ b/iconv_charmap-Close-output-file-when-done.patch @@ -0,0 +1,26 @@ +From 1e0e6d656db9dfa12ef7eb67976385d3deb0d4ff Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +Date: Tue, 3 Aug 2021 21:10:29 +0530 +Subject: [PATCH] iconv_charmap: Close output file when done + +Reviewed-by: Arjun Shankar +--- + iconv/iconv_charmap.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/iconv/iconv_charmap.c b/iconv/iconv_charmap.c +index e2d53fe..a8b6b56 100644 +--- a/iconv/iconv_charmap.c ++++ b/iconv/iconv_charmap.c +@@ -234,6 +234,8 @@ charmap_conversion (const char *from_code, struct charmap_t *from_charmap, + while (++remaining < argc); + + /* All done. */ ++ if (output != stdout) ++ fclose (output); + free_table (cvtbl); + return status; + } +-- +1.8.3.1 + diff --git a/iconvconfig-Fix-behaviour-with-prefix-BZ-28199.patch b/iconvconfig-Fix-behaviour-with-prefix-BZ-28199.patch new file mode 100644 index 0000000000000000000000000000000000000000..6df7a8218cf4f111faf3f08beff2506fd553488b --- /dev/null +++ b/iconvconfig-Fix-behaviour-with-prefix-BZ-28199.patch @@ -0,0 +1,123 @@ +From 43cea6d5652b6b9e61ac6ecc69419c909b504f47 Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +Date: Mon, 13 Sep 2021 20:48:35 +0530 +Subject: [PATCH] iconvconfig: Fix behaviour with --prefix [BZ #28199] + +The consolidation of configuration parsing broke behaviour with +--prefix, where the prefix bled into the modules cache. Accept a +prefix which, when non-NULL, is prepended to the path when looking for +configuration files but only the original directory is added to the +modules cache. + +This has no effect on the codegen of gconv_conf since it passes NULL. + +Reported-by: Patrick McCarty +Reported-by: Michael Hudson-Doyle +Reviewed-by: Andreas Schwab +--- + iconv/gconv_conf.c | 2 +- + iconv/gconv_parseconfdir.h | 22 +++++++++++++++------- + iconv/iconvconfig.c | 16 ++++++++++++---- + 3 files changed, 28 insertions(+), 12 deletions(-) + +diff --git a/iconv/gconv_conf.c b/iconv/gconv_conf.c +index 09ffe02..077082a 100644 +--- a/iconv/gconv_conf.c ++++ b/iconv/gconv_conf.c +@@ -477,7 +477,7 @@ __gconv_read_conf (void) + __gconv_get_path (); + + for (cnt = 0; __gconv_path_elem[cnt].name != NULL; ++cnt) +- gconv_parseconfdir (__gconv_path_elem[cnt].name, ++ gconv_parseconfdir (NULL, __gconv_path_elem[cnt].name, + __gconv_path_elem[cnt].len); + #endif + +diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h +index 2f06268..a586268 100644 +--- a/iconv/gconv_parseconfdir.h ++++ b/iconv/gconv_parseconfdir.h +@@ -39,7 +39,6 @@ + /* Name of the file containing the module information in the directories + along the path. */ + static const char gconv_conf_filename[] = "gconv-modules"; +-static const char gconv_conf_dirname[] = "gconv-modules.d"; + + static void add_alias (char *); + static void add_module (char *, const char *, size_t, int); +@@ -110,19 +109,28 @@ read_conf_file (const char *filename, const char *directory, size_t dir_len) + return true; + } + ++/* Prefix DIR (with length DIR_LEN) with PREFIX if the latter is non-NULL and ++ parse configuration in it. */ ++ + static __always_inline bool +-gconv_parseconfdir (const char *dir, size_t dir_len) ++gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len) + { +- /* No slash needs to be inserted between dir and gconv_conf_filename; +- dir already ends in a slash. */ +- char *buf = malloc (dir_len + sizeof (gconv_conf_dirname)); ++ /* No slash needs to be inserted between dir and gconv_conf_filename; dir ++ already ends in a slash. The additional 2 is to accommodate the ".d" ++ when looking for configuration files in gconv-modules.d. */ ++ size_t buflen = dir_len + sizeof (gconv_conf_filename) + 2; ++ char *buf = malloc (buflen + (prefix != NULL ? strlen (prefix) : 0)); ++ char *cp = buf; + bool found = false; + + if (buf == NULL) + return false; + +- char *cp = mempcpy (mempcpy (buf, dir, dir_len), gconv_conf_filename, +- sizeof (gconv_conf_filename)); ++ if (prefix != NULL) ++ cp = stpcpy (cp, prefix); ++ ++ cp = mempcpy (mempcpy (cp, dir, dir_len), gconv_conf_filename, ++ sizeof (gconv_conf_filename)); + + /* Read the gconv-modules configuration file first. */ + found = read_conf_file (buf, dir, dir_len); +diff --git a/iconv/iconvconfig.c b/iconv/iconvconfig.c +index fd61cf2..a89b62e 100644 +--- a/iconv/iconvconfig.c ++++ b/iconv/iconvconfig.c +@@ -652,13 +652,21 @@ add_module (char *rp, const char *directory, + static int + handle_dir (const char *dir) + { ++ char *newp = NULL; + size_t dirlen = strlen (dir); + bool found = false; + +- char *fulldir = xasprintf ("%s%s%s", dir[0] == '/' ? prefix : "", +- dir, dir[dirlen - 1] != '/' ? "/" : ""); ++ /* End directory path with a '/' if it doesn't already. */ ++ if (dir[dirlen - 1] != '/') ++ { ++ newp = xmalloc (dirlen + 2); ++ memcpy (newp, dir, dirlen); ++ newp[dirlen++] = '/'; ++ newp[dirlen] = '\0'; ++ dir = newp; ++ } + +- found = gconv_parseconfdir (fulldir, strlen (fulldir)); ++ found = gconv_parseconfdir (dir[0] == '/' ? prefix : NULL, dir, dirlen); + + if (!found) + { +@@ -670,7 +678,7 @@ handle_dir (const char *dir) + "configuration files with names ending in .conf."); + } + +- free (fulldir); ++ free (newp); + + return found ? 0 : 1; + } +-- +1.8.3.1 + diff --git a/intl-plural.y-Avoid-conflicting-declarations-of-yyer.patch b/intl-plural.y-Avoid-conflicting-declarations-of-yyer.patch new file mode 100644 index 0000000000000000000000000000000000000000..4931c9e5ba686767b088a5701052c6264fd5b645 --- /dev/null +++ b/intl-plural.y-Avoid-conflicting-declarations-of-yyer.patch @@ -0,0 +1,42 @@ +From c6d7d6312c21bbcfb236d48bb7c11cedb234389f Mon Sep 17 00:00:00 2001 +From: Andrea Monaco +Date: Sun, 12 Dec 2021 10:24:28 +0100 +Subject: [PATCH] intl/plural.y: Avoid conflicting declarations of yyerror and + yylex + +bison-3.8 includes these lines in the generated intl/plural.c: + + #if !defined __gettexterror && !defined YYERROR_IS_DECLARED + void __gettexterror (struct parse_args *arg, const char *msg); + #endif + #if !defined __gettextlex && !defined YYLEX_IS_DECLARED + int __gettextlex (YYSTYPE *yylvalp, struct parse_args *arg); + #endif + +Those default prototypes provided by bison conflict with the +declarations later on in plural.y. This patch solves the issue. + +Reviewed-by: Arjun Shankar +--- + intl/plural.y | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/intl/plural.y b/intl/plural.y +index e02e745..2ee128b 100644 +--- a/intl/plural.y ++++ b/intl/plural.y +@@ -40,6 +40,11 @@ + # define __gettextparse PLURAL_PARSE + #endif + ++/* Later we provide those prototypes. Without these macros, bison may ++ generate its own prototypes with possible conflicts. */ ++#define YYLEX_IS_DECLARED ++#define YYERROR_IS_DECLARED ++ + %} + %parse-param {struct parse_args *arg} + %lex-param {struct parse_args *arg} +-- +1.8.3.1 + diff --git a/io-Fix-ftw-internal-realloc-buffer-BZ-28126.patch b/io-Fix-ftw-internal-realloc-buffer-BZ-28126.patch new file mode 100644 index 0000000000000000000000000000000000000000..09767bd715da61ad8fe726b9273406e0c2cbaf00 --- /dev/null +++ b/io-Fix-ftw-internal-realloc-buffer-BZ-28126.patch @@ -0,0 +1,210 @@ +From 1836bb2ebf62bd9a3588f2ed2d851c8ae810097a Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Wed, 25 Aug 2021 11:17:06 -0300 +Subject: [PATCH] io: Fix ftw internal realloc buffer (BZ #28126) + +The 106ff08526d3ca did not take in consideration the buffer might be +reallocated if the total path is larger than PATH_MAX. The realloc +uses 'dirbuf', where 'dirstreams' is the allocated buffer. + +Checked on x86_64-linux-gnu. + +Reviewed-by: H.J. Lu +--- + io/Makefile | 1 + + io/ftw.c | 39 ++++++++++----------- + io/tst-ftw-bz28126.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 117 insertions(+), 20 deletions(-) + create mode 100644 io/tst-ftw-bz28126.c + +diff --git a/io/Makefile b/io/Makefile +index 9871ecb..ecf65ab 100644 +--- a/io/Makefile ++++ b/io/Makefile +@@ -79,6 +79,7 @@ tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \ + tst-futimens \ + tst-utimensat \ + tst-closefrom \ ++ tst-ftw-bz28126 + + tests-time64 := \ + tst-futimens-time64 \ +diff --git a/io/ftw.c b/io/ftw.c +index f0db173..fe95345 100644 +--- a/io/ftw.c ++++ b/io/ftw.c +@@ -203,6 +203,20 @@ struct ftw_data + void *known_objects; + }; + ++static bool ++ftw_allocate (struct ftw_data *data, size_t newsize) ++{ ++ void *newp = realloc (data->dirstreams, data->maxdir ++ * sizeof (struct dir_data *) ++ + newsize); ++ if (newp == NULL) ++ return false; ++ data->dirstreams = newp; ++ data->dirbufsize = newsize; ++ data->dirbuf = (char *) data->dirstreams ++ + data->maxdir * sizeof (struct dir_data *); ++ return true; ++} + + /* Internally we use the FTW_* constants used for `nftw'. When invoked + as `ftw', map each flag to the subset of values used by `ftw'. */ +@@ -388,17 +402,9 @@ process_entry (struct ftw_data *data, struct dir_data *dir, const char *name, + return 0; + + new_buflen = data->ftw.base + namlen + 2; +- if (data->dirbufsize < new_buflen) +- { +- /* Enlarge the buffer. */ +- char *newp; +- +- data->dirbufsize = 2 * new_buflen; +- newp = (char *) realloc (data->dirbuf, data->dirbufsize); +- if (newp == NULL) +- return -1; +- data->dirbuf = newp; +- } ++ if (data->dirbufsize < new_buflen ++ && !ftw_allocate (data, 2 * new_buflen)) ++ return -1; + + *((char *) __mempcpy (data->dirbuf + data->ftw.base, name, namlen)) = '\0'; + +@@ -628,7 +634,7 @@ __attribute ((noinline)) + ftw_startup (const char *dir, int is_nftw, void *func, int descriptors, + int flags) + { +- struct ftw_data data; ++ struct ftw_data data = { .dirstreams = NULL }; + struct STRUCT_STAT st; + int result = 0; + int save_err; +@@ -646,16 +652,9 @@ ftw_startup (const char *dir, int is_nftw, void *func, int descriptors, + data.maxdir = descriptors < 1 ? 1 : descriptors; + data.actdir = 0; + /* PATH_MAX is always defined when we get here. */ +- data.dirbufsize = MAX (2 * strlen (dir), PATH_MAX); +- data.dirstreams = malloc (data.maxdir * sizeof (struct dir_data *) +- + data.dirbufsize); +- if (data.dirstreams == NULL) ++ if (!ftw_allocate (&data, MAX (2 * strlen (dir), PATH_MAX))) + return -1; +- + memset (data.dirstreams, '\0', data.maxdir * sizeof (struct dir_data *)); +- +- data.dirbuf = (char *) data.dirstreams +- + data.maxdir * sizeof (struct dir_data *); + cp = __stpcpy (data.dirbuf, dir); + /* Strip trailing slashes. */ + while (cp > data.dirbuf + 1 && cp[-1] == '/') +diff --git a/io/tst-ftw-bz28126.c b/io/tst-ftw-bz28126.c +new file mode 100644 +index 0000000..94044ab +--- /dev/null ++++ b/io/tst-ftw-bz28126.c +@@ -0,0 +1,97 @@ ++/* Check if internal buffer reallocation work for large paths (BZ #28126) ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++my_func (const char *file, const struct stat *sb, int flag) ++{ ++ return 0; ++} ++ ++static const char folder[NAME_MAX] = { [0 ... 253] = 'a', [254] = '\0' }; ++ ++#define NSUBFOLDERS 16 ++static int nsubfolders; ++ ++static void ++do_cleanup (void) ++{ ++ xchdir (".."); ++ for (int i = 0; i < nsubfolders; i++) ++ { ++ remove (folder); ++ xchdir (".."); ++ } ++ remove (folder); ++} ++#define CLEANUP_HANDLER do_cleanup ++ ++static void ++check_mkdir (const char *path) ++{ ++ int r = mkdir (path, 0777); ++ /* Some filesystem such as overlayfs does not support larger path required ++ to trigger the internal buffer reallocation. */ ++ if (r != 0) ++ { ++ if (errno == ENAMETOOLONG) ++ FAIL_UNSUPPORTED ("the filesystem does not support the required" ++ "large path"); ++ else ++ FAIL_EXIT1 ("mkdir (\"%s\", 0%o): %m", folder, 0777); ++ } ++} ++ ++static int ++do_test (void) ++{ ++ char *tempdir = support_create_temp_directory ("tst-bz28126"); ++ ++ /* Create path with various subfolders to force an internal buffer ++ reallocation within ntfw. */ ++ char *path = xasprintf ("%s/%s", tempdir, folder); ++ check_mkdir (path); ++ xchdir (path); ++ free (path); ++ for (int i = 0; i < NSUBFOLDERS - 1; i++) ++ { ++ check_mkdir (folder); ++ xchdir (folder); ++ nsubfolders++; ++ } ++ ++ TEST_COMPARE (ftw (tempdir, my_func, 20), 0); ++ ++ free (tempdir); ++ ++ do_cleanup (); ++ ++ return 0; ++} ++ ++#include +-- +1.8.3.1 + diff --git a/ld.so-Don-t-fill-the-DT_DEBUG-entry-in-ld.so-BZ-2812.patch b/ld.so-Don-t-fill-the-DT_DEBUG-entry-in-ld.so-BZ-2812.patch new file mode 100644 index 0000000000000000000000000000000000000000..93d45e947a0f8a677add72c73b9fdfba9256fbf0 --- /dev/null +++ b/ld.so-Don-t-fill-the-DT_DEBUG-entry-in-ld.so-BZ-2812.patch @@ -0,0 +1,37 @@ +From 3234a31b489707f19ec6d4c9909af06f20ddb901 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Mon, 2 Aug 2021 13:52:36 -0700 +Subject: [PATCH] ld.so: Don't fill the DT_DEBUG entry in ld.so [BZ #28129] + +Linker creates the DT_DEBUG entry only in executables. Don't fill the +non-existent DT_DEBUG entry in ld.so with the run-time address of the +r_debug structure. This fixes BZ #28129. +--- + elf/rtld.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/elf/rtld.c b/elf/rtld.c +index 9642eb9c92..628245d8cd 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -1761,17 +1761,11 @@ dl_main (const ElfW(Phdr) *phdr, + #ifdef ELF_MACHINE_DEBUG_SETUP + /* Some machines (e.g. MIPS) don't use DT_DEBUG in this way. */ + ELF_MACHINE_DEBUG_SETUP (main_map, r); +- ELF_MACHINE_DEBUG_SETUP (&GL(dl_rtld_map), r); + #else + if (main_map->l_info[DT_DEBUG] != NULL) + /* There is a DT_DEBUG entry in the dynamic section. Fill it in + with the run-time address of the r_debug structure */ + main_map->l_info[DT_DEBUG]->d_un.d_ptr = (ElfW(Addr)) r; +- +- /* Fill in the pointer in the dynamic linker's own dynamic section, in +- case you run gdb on the dynamic linker directly. */ +- if (GL(dl_rtld_map).l_info[DT_DEBUG] != NULL) +- GL(dl_rtld_map).l_info[DT_DEBUG]->d_un.d_ptr = (ElfW(Addr)) r; + #endif + + /* We start adding objects. */ +-- +2.25.1 + diff --git a/ld.so-Initialize-bootstrap_map.l_ld_readonly-BZ-2834.patch b/ld.so-Initialize-bootstrap_map.l_ld_readonly-BZ-2834.patch new file mode 100644 index 0000000000000000000000000000000000000000..d1f4271f5367a46f0536aa14fa3d4c40f02a8f96 --- /dev/null +++ b/ld.so-Initialize-bootstrap_map.l_ld_readonly-BZ-2834.patch @@ -0,0 +1,124 @@ +From 2ec99d8c42b2ff1a1231e4df462a0910a9b7fdef Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Thu, 23 Sep 2021 09:06:49 -0700 +Subject: [PATCH] ld.so: Initialize bootstrap_map.l_ld_readonly [BZ #28340] + +1. Define DL_RO_DYN_SECTION to initalize bootstrap_map.l_ld_readonly +before calling elf_get_dynamic_info to get dynamic info in bootstrap_map, +2. Define a single + +static inline bool +dl_relocate_ld (const struct link_map *l) +{ + /* Don't relocate dynamic section if it is readonly */ + return !(l->l_ld_readonly || DL_RO_DYN_SECTION); +} + +This updates BZ #28340 fix. +--- + elf/rtld.c | 1 + + sysdeps/generic/dl-relocate-ld.h | 11 ++--------- + sysdeps/generic/ldsodefs.h | 10 ++++++++++ + sysdeps/mips/dl-relocate-ld.h | 11 ++--------- + sysdeps/riscv/dl-relocate-ld.h | 11 ++--------- + 5 files changed, 17 insertions(+), 27 deletions(-) + +diff --git a/elf/rtld.c b/elf/rtld.c +index c66a1d0..b8ba2d8 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -547,6 +547,7 @@ _dl_start (void *arg) + + /* Read our own dynamic section and fill in the info array. */ + bootstrap_map.l_ld = (void *) bootstrap_map.l_addr + elf_machine_dynamic (); ++ bootstrap_map.l_ld_readonly = DL_RO_DYN_SECTION; + elf_get_dynamic_info (&bootstrap_map); + + #if NO_TLS_OFFSET != 0 +diff --git a/sysdeps/generic/dl-relocate-ld.h b/sysdeps/generic/dl-relocate-ld.h +index 5fae206..cfb86c2 100644 +--- a/sysdeps/generic/dl-relocate-ld.h ++++ b/sysdeps/generic/dl-relocate-ld.h +@@ -19,14 +19,7 @@ + #ifndef _DL_RELOCATE_LD_H + #define _DL_RELOCATE_LD_H + +-/* Return true if dynamic section in the shared library L should be +- relocated. */ +- +-static inline bool +-dl_relocate_ld (const struct link_map *l) +-{ +- /* Don't relocate dynamic section if it is readonly */ +- return !l->l_ld_readonly; +-} ++/* The dynamic section is writable. */ ++#define DL_RO_DYN_SECTION 0 + + #endif /* _DL_RELOCATE_LD_H */ +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 9ec1511..0410f77 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -69,6 +69,16 @@ __BEGIN_DECLS + `ElfW(TYPE)' is used in place of `Elf32_TYPE' or `Elf64_TYPE'. */ + #define ELFW(type) _ElfW (ELF, __ELF_NATIVE_CLASS, type) + ++/* Return true if dynamic section in the shared library L should be ++ relocated. */ ++ ++static inline bool ++dl_relocate_ld (const struct link_map *l) ++{ ++ /* Don't relocate dynamic section if it is readonly */ ++ return !(l->l_ld_readonly || DL_RO_DYN_SECTION); ++} ++ + /* All references to the value of l_info[DT_PLTGOT], + l_info[DT_STRTAB], l_info[DT_SYMTAB], l_info[DT_RELA], + l_info[DT_REL], l_info[DT_JMPREL], and l_info[VERSYMIDX (DT_VERSYM)] +diff --git a/sysdeps/mips/dl-relocate-ld.h b/sysdeps/mips/dl-relocate-ld.h +index 0c18d9a..376ad75 100644 +--- a/sysdeps/mips/dl-relocate-ld.h ++++ b/sysdeps/mips/dl-relocate-ld.h +@@ -19,14 +19,7 @@ + #ifndef _DL_RELOCATE_LD_H + #define _DL_RELOCATE_LD_H + +-/* Return true if dynamic section in the shared library L should be +- relocated. */ +- +-static inline bool +-dl_relocate_ld (const struct link_map *l) +-{ +- /* Never relocate dynamic section. */ +- return false; +-} ++/* The dynamic section is readonly. */ ++#define DL_RO_DYN_SECTION 1 + + #endif /* _DL_RELOCATE_LD_H */ +diff --git a/sysdeps/riscv/dl-relocate-ld.h b/sysdeps/riscv/dl-relocate-ld.h +index 1032745..2ab2b8a 100644 +--- a/sysdeps/riscv/dl-relocate-ld.h ++++ b/sysdeps/riscv/dl-relocate-ld.h +@@ -19,14 +19,7 @@ + #ifndef _DL_RELOCATE_LD_H + #define _DL_RELOCATE_LD_H + +-/* Return true if dynamic section in the shared library L should be +- relocated. */ +- +-static inline bool +-dl_relocate_ld (const struct link_map *l) +-{ +- /* Never relocate dynamic section for ABI compatibility. */ +- return false; +-} ++/* The dynamic section is readonly for ABI compatibility. */ ++#define DL_RO_DYN_SECTION 1 + + #endif /* _DL_RELOCATE_LD_H */ +-- +1.8.3.1 + diff --git a/ld.so-Replace-DL_RO_DYN_SECTION-with-dl_relocate_ld-.patch b/ld.so-Replace-DL_RO_DYN_SECTION-with-dl_relocate_ld-.patch new file mode 100644 index 0000000000000000000000000000000000000000..077b996743c1a88b817e7935e7fbc8fdded4684c --- /dev/null +++ b/ld.so-Replace-DL_RO_DYN_SECTION-with-dl_relocate_ld-.patch @@ -0,0 +1,515 @@ +From b413280cfb16834450f66f554bc0d618bb513851 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Thu, 16 Sep 2021 08:15:29 -0700 +Subject: [PATCH] ld.so: Replace DL_RO_DYN_SECTION with dl_relocate_ld [BZ + #28340] + +We can't relocate entries in dynamic section if it is readonly: + +1. Add a l_ld_readonly field to struct link_map to indicate if dynamic +section is readonly and set it based on p_flags of PT_DYNAMIC segment. +2. Replace DL_RO_DYN_SECTION with dl_relocate_ld to decide if dynamic +section should be relocated. +3. Remove DL_RO_DYN_TEMP_CNT. +4. Don't use a static dynamic section to make readonly dynamic section +in vDSO writable. +5. Remove the temp argument from elf_get_dynamic_info. + +This fixes BZ #28340. + +Reviewed-by: Siddhesh Poyarekar +--- + elf/Makefile | 11 +++++++++-- + elf/dl-load.c | 3 ++- + elf/dl-reloc-static-pie.c | 12 +++++++++++- + elf/get-dynamic-info.h | 21 +++------------------ + elf/rtld.c | 6 ++++-- + elf/setup-vdso.h | 5 ++--- + elf/tst-ro-dynamic-mod.c | 19 +++++++++++++++++++ + elf/tst-ro-dynamic-mod.map | 16 ++++++++++++++++ + elf/tst-ro-dynamic.c | 31 +++++++++++++++++++++++++++++++ + include/link.h | 3 +++ + sysdeps/generic/dl-relocate-ld.h | 32 ++++++++++++++++++++++++++++++++ + sysdeps/generic/ldsodefs.h | 7 ++----- + sysdeps/mips/dl-relocate-ld.h | 32 ++++++++++++++++++++++++++++++++ + sysdeps/mips/ldsodefs.h | 4 ---- + sysdeps/riscv/dl-relocate-ld.h | 32 ++++++++++++++++++++++++++++++++ + sysdeps/riscv/ldsodefs.h | 5 ----- + 16 files changed, 198 insertions(+), 41 deletions(-) + create mode 100644 elf/tst-ro-dynamic-mod.c + create mode 100644 elf/tst-ro-dynamic-mod.map + create mode 100644 elf/tst-ro-dynamic.c + create mode 100644 sysdeps/generic/dl-relocate-ld.h + create mode 100644 sysdeps/mips/dl-relocate-ld.h + create mode 100644 sysdeps/riscv/dl-relocate-ld.h + +diff --git a/elf/Makefile b/elf/Makefile +index 835b85b..0cdccaa 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -224,7 +224,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-tls-ie tst-tls-ie-dlmopen argv0test \ + tst-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask \ + tst-tls20 tst-tls21 tst-dlmopen-dlerror tst-dlmopen-gethostbyname \ +- tst-dl-is_dso ++ tst-dl-is_dso tst-ro-dynamic + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -360,7 +360,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + libmarkermod4-1 libmarkermod4-2 libmarkermod4-3 libmarkermod4-4 \ + tst-tls20mod-bad tst-tls21mod tst-dlmopen-dlerror-mod \ + tst-auxvalmod \ +- tst-dlmopen-gethostbyname-mod \ ++ tst-dlmopen-gethostbyname-mod tst-ro-dynamic-mod \ + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. +@@ -1911,3 +1911,10 @@ $(objpfx)tst-getauxval-static.out: $(objpfx)tst-auxvalmod.so + tst-getauxval-static-ENV = LD_LIBRARY_PATH=$(objpfx):$(common-objpfx) + + $(objpfx)tst-dlmopen-gethostbyname.out: $(objpfx)tst-dlmopen-gethostbyname-mod.so ++ ++$(objpfx)tst-ro-dynamic: $(objpfx)tst-ro-dynamic-mod.so ++$(objpfx)tst-ro-dynamic-mod.so: $(objpfx)tst-ro-dynamic-mod.os \ ++ tst-ro-dynamic-mod.map ++ $(LINK.o) -nostdlib -nostartfiles -shared -o $@ \ ++ -Wl,--script=tst-ro-dynamic-mod.map \ ++ $(objpfx)tst-ro-dynamic-mod.os +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 39e0d07..6ea7107 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -1149,6 +1149,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + such a segment to avoid a crash later. */ + l->l_ld = (void *) ph->p_vaddr; + l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn)); ++ l->l_ld_readonly = (ph->p_flags & PF_W) == 0; + } + break; + +@@ -1292,7 +1293,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + else + l->l_ld = (ElfW(Dyn) *) ((ElfW(Addr)) l->l_ld + l->l_addr); + +- elf_get_dynamic_info (l, NULL); ++ elf_get_dynamic_info (l); + + /* Make sure we are not dlopen'ing an object that has the + DF_1_NOOPEN flag set, or a PIE object. */ +diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c +index 289651b..68ded17 100644 +--- a/elf/dl-reloc-static-pie.c ++++ b/elf/dl-reloc-static-pie.c +@@ -40,7 +40,17 @@ _dl_relocate_static_pie (void) + + /* Read our own dynamic section and fill in the info array. */ + main_map->l_ld = ((void *) main_map->l_addr + elf_machine_dynamic ()); +- elf_get_dynamic_info (main_map, NULL); ++ ++ const ElfW(Phdr) *ph, *phdr = GL(dl_phdr); ++ size_t phnum = GL(dl_phnum); ++ for (ph = phdr; ph < &phdr[phnum]; ++ph) ++ if (ph->p_type == PT_DYNAMIC) ++ { ++ main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0; ++ break; ++ } ++ ++ elf_get_dynamic_info (main_map); + + # ifdef ELF_MACHINE_BEFORE_RTLD_RELOC + ELF_MACHINE_BEFORE_RTLD_RELOC (main_map->l_info); +diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h +index d8ec323..4aa2058 100644 +--- a/elf/get-dynamic-info.h ++++ b/elf/get-dynamic-info.h +@@ -28,7 +28,7 @@ static + auto + #endif + inline void __attribute__ ((unused, always_inline)) +-elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) ++elf_get_dynamic_info (struct link_map *l) + { + #if __ELF_NATIVE_CLASS == 32 + typedef Elf32_Word d_tag_utype; +@@ -69,28 +69,15 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) + info[i] = dyn; + } + +-#define DL_RO_DYN_TEMP_CNT 8 +- +-#ifndef DL_RO_DYN_SECTION + /* Don't adjust .dynamic unnecessarily. */ +- if (l->l_addr != 0) ++ if (l->l_addr != 0 && dl_relocate_ld (l)) + { + ElfW(Addr) l_addr = l->l_addr; +- int cnt = 0; + + # define ADJUST_DYN_INFO(tag) \ + do \ + if (info[tag] != NULL) \ +- { \ +- if (temp) \ +- { \ +- temp[cnt].d_tag = info[tag]->d_tag; \ +- temp[cnt].d_un.d_ptr = info[tag]->d_un.d_ptr + l_addr; \ +- info[tag] = temp + cnt++; \ +- } \ +- else \ +- info[tag]->d_un.d_ptr += l_addr; \ +- } \ ++ info[tag]->d_un.d_ptr += l_addr; \ + while (0) + + ADJUST_DYN_INFO (DT_HASH); +@@ -107,9 +94,7 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) + ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM)); + ADJUST_DYN_INFO (ADDRIDX (DT_GNU_HASH)); + # undef ADJUST_DYN_INFO +- assert (cnt <= DL_RO_DYN_TEMP_CNT); + } +-#endif + if (info[DT_PLTREL] != NULL) + { + #if ELF_MACHINE_NO_RELA +diff --git a/elf/rtld.c b/elf/rtld.c +index 742c413..8d2bba3 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -463,6 +463,7 @@ _dl_start_final (void *arg, struct dl_start_final_info *info) + #ifndef DONT_USE_BOOTSTRAP_MAP + GL(dl_rtld_map).l_addr = info->l.l_addr; + GL(dl_rtld_map).l_ld = info->l.l_ld; ++ GL(dl_rtld_map).l_ld_readonly = info->l.l_ld_readonly; + memcpy (GL(dl_rtld_map).l_info, info->l.l_info, + sizeof GL(dl_rtld_map).l_info); + GL(dl_rtld_map).l_mach = info->l.l_mach; +@@ -546,7 +547,7 @@ _dl_start (void *arg) + + /* Read our own dynamic section and fill in the info array. */ + bootstrap_map.l_ld = (void *) bootstrap_map.l_addr + elf_machine_dynamic (); +- elf_get_dynamic_info (&bootstrap_map, NULL); ++ elf_get_dynamic_info (&bootstrap_map); + + #if NO_TLS_OFFSET != 0 + bootstrap_map.l_tls_offset = NO_TLS_OFFSET; +@@ -1468,6 +1469,7 @@ dl_main (const ElfW(Phdr) *phdr, + /* This tells us where to find the dynamic section, + which tells us everything we need to do. */ + main_map->l_ld = (void *) main_map->l_addr + ph->p_vaddr; ++ main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0; + break; + case PT_INTERP: + /* This "interpreter segment" was used by the program loader to +@@ -1613,7 +1615,7 @@ dl_main (const ElfW(Phdr) *phdr, + if (! rtld_is_main) + { + /* Extract the contents of the dynamic section for easy access. */ +- elf_get_dynamic_info (main_map, NULL); ++ elf_get_dynamic_info (main_map); + + /* If the main map is libc.so, update the base namespace to + refer to this map. If libc.so is loaded later, this happens +diff --git a/elf/setup-vdso.h b/elf/setup-vdso.h +index 86c491e..f44748b 100644 +--- a/elf/setup-vdso.h ++++ b/elf/setup-vdso.h +@@ -33,8 +33,6 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)), + 0, LM_ID_BASE); + if (__glibc_likely (l != NULL)) + { +- static ElfW(Dyn) dyn_temp[DL_RO_DYN_TEMP_CNT] attribute_relro; +- + l->l_phdr = ((const void *) GLRO(dl_sysinfo_dso) + + GLRO(dl_sysinfo_dso)->e_phoff); + l->l_phnum = GLRO(dl_sysinfo_dso)->e_phnum; +@@ -45,6 +43,7 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)), + { + l->l_ld = (void *) ph->p_vaddr; + l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn)); ++ l->l_ld_readonly = (ph->p_flags & PF_W) == 0; + } + else if (ph->p_type == PT_LOAD) + { +@@ -65,7 +64,7 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)), + l->l_map_end += l->l_addr; + l->l_text_end += l->l_addr; + l->l_ld = (void *) ((ElfW(Addr)) l->l_ld + l->l_addr); +- elf_get_dynamic_info (l, dyn_temp); ++ elf_get_dynamic_info (l); + _dl_setup_hash (l); + l->l_relocated = 1; + +diff --git a/elf/tst-ro-dynamic-mod.c b/elf/tst-ro-dynamic-mod.c +new file mode 100644 +index 0000000..6d99925 +--- /dev/null ++++ b/elf/tst-ro-dynamic-mod.c +@@ -0,0 +1,19 @@ ++/* Test case for DSO with readonly dynamic section. ++ 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 ++ . */ ++ ++int foo = -1; +diff --git a/elf/tst-ro-dynamic-mod.map b/elf/tst-ro-dynamic-mod.map +new file mode 100644 +index 0000000..2fe4a29 +--- /dev/null ++++ b/elf/tst-ro-dynamic-mod.map +@@ -0,0 +1,16 @@ ++SECTIONS ++{ ++ . = SIZEOF_HEADERS; ++ .dynamic : { *(.dynamic) } :text :dynamic ++ .rodata : { *(.data*) *(.bss*) } :text ++ /DISCARD/ : { ++ *(.note.gnu.property) ++ } ++ .note : { *(.note.*) } :text :note ++} ++PHDRS ++{ ++ text PT_LOAD FLAGS(5) FILEHDR PHDRS; ++ dynamic PT_DYNAMIC FLAGS(4); ++ note PT_NOTE FLAGS(4); ++} +diff --git a/elf/tst-ro-dynamic.c b/elf/tst-ro-dynamic.c +new file mode 100644 +index 0000000..3a18f87 +--- /dev/null ++++ b/elf/tst-ro-dynamic.c +@@ -0,0 +1,31 @@ ++/* Test case for DSO with readonly dynamic section. ++ 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 ++ . */ ++ ++#include ++#include ++ ++extern int foo; ++ ++static int ++do_test (void) ++{ ++ TEST_COMPARE (foo, -1); ++ return 0; ++} ++ ++#include +diff --git a/include/link.h b/include/link.h +index 7b8250d..484ee6c 100644 +--- a/include/link.h ++++ b/include/link.h +@@ -205,6 +205,7 @@ struct link_map + unsigned int l_free_initfini:1; /* Nonzero if l_initfini can be + freed, ie. not allocated with + the dummy malloc in ld.so. */ ++ unsigned int l_ld_readonly:1; /* Nonzero if dynamic section is readonly. */ + + /* NODELETE status of the map. Only valid for maps of type + lt_loaded. Lazy binding sets l_nodelete_active directly, +@@ -342,6 +343,8 @@ struct link_map + unsigned long long int l_serial; + }; + ++#include ++ + /* Information used by audit modules. For most link maps, this data + immediate follows the link map in memory. For the dynamic linker, + it is allocated separately. See link_map_audit_state in +diff --git a/sysdeps/generic/dl-relocate-ld.h b/sysdeps/generic/dl-relocate-ld.h +new file mode 100644 +index 0000000..5fae206 +--- /dev/null ++++ b/sysdeps/generic/dl-relocate-ld.h +@@ -0,0 +1,32 @@ ++/* Check if dynamic section should be relocated. Generic version. ++ 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 ++ . */ ++ ++#ifndef _DL_RELOCATE_LD_H ++#define _DL_RELOCATE_LD_H ++ ++/* Return true if dynamic section in the shared library L should be ++ relocated. */ ++ ++static inline bool ++dl_relocate_ld (const struct link_map *l) ++{ ++ /* Don't relocate dynamic section if it is readonly */ ++ return !l->l_ld_readonly; ++} ++ ++#endif /* _DL_RELOCATE_LD_H */ +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 6e50fcd..d49529d 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -75,11 +75,8 @@ __BEGIN_DECLS + have to be accessed via the D_PTR macro. The macro is needed since for + most architectures the entry is already relocated - but for some not + and we need to relocate at access time. */ +-#ifdef DL_RO_DYN_SECTION +-# define D_PTR(map, i) ((map)->i->d_un.d_ptr + (map)->l_addr) +-#else +-# define D_PTR(map, i) (map)->i->d_un.d_ptr +-#endif ++#define D_PTR(map, i) \ ++ ((map)->i->d_un.d_ptr + (dl_relocate_ld (map) ? 0 : (map)->l_addr)) + + /* Result of the lookup functions and how to retrieve the base address. */ + typedef struct link_map *lookup_t; +diff --git a/sysdeps/mips/dl-relocate-ld.h b/sysdeps/mips/dl-relocate-ld.h +new file mode 100644 +index 0000000..0c18d9a +--- /dev/null ++++ b/sysdeps/mips/dl-relocate-ld.h +@@ -0,0 +1,32 @@ ++/* Check if dynamic section should be relocated. MIPS version. ++ 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 ++ . */ ++ ++#ifndef _DL_RELOCATE_LD_H ++#define _DL_RELOCATE_LD_H ++ ++/* Return true if dynamic section in the shared library L should be ++ relocated. */ ++ ++static inline bool ++dl_relocate_ld (const struct link_map *l) ++{ ++ /* Never relocate dynamic section. */ ++ return false; ++} ++ ++#endif /* _DL_RELOCATE_LD_H */ +diff --git a/sysdeps/mips/ldsodefs.h b/sysdeps/mips/ldsodefs.h +index 4db7c60..36fd09a 100644 +--- a/sysdeps/mips/ldsodefs.h ++++ b/sysdeps/mips/ldsodefs.h +@@ -75,10 +75,6 @@ struct La_mips_64_retval; + struct La_mips_64_retval *, \ + const char *); + +-/* The MIPS ABI specifies that the dynamic section has to be read-only. */ +- +-#define DL_RO_DYN_SECTION 1 +- + #include_next + + /* The 64-bit MIPS ELF ABI uses an unusual reloc format. Each +diff --git a/sysdeps/riscv/dl-relocate-ld.h b/sysdeps/riscv/dl-relocate-ld.h +new file mode 100644 +index 0000000..1032745 +--- /dev/null ++++ b/sysdeps/riscv/dl-relocate-ld.h +@@ -0,0 +1,32 @@ ++/* Check if dynamic section should be relocated. RISC-V version. ++ 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 ++ . */ ++ ++#ifndef _DL_RELOCATE_LD_H ++#define _DL_RELOCATE_LD_H ++ ++/* Return true if dynamic section in the shared library L should be ++ relocated. */ ++ ++static inline bool ++dl_relocate_ld (const struct link_map *l) ++{ ++ /* Never relocate dynamic section for ABI compatibility. */ ++ return false; ++} ++ ++#endif /* _DL_RELOCATE_LD_H */ +diff --git a/sysdeps/riscv/ldsodefs.h b/sysdeps/riscv/ldsodefs.h +index 0c69671..8947ffe 100644 +--- a/sysdeps/riscv/ldsodefs.h ++++ b/sysdeps/riscv/ldsodefs.h +@@ -38,11 +38,6 @@ struct La_riscv_retval; + struct La_riscv_retval *, \ + const char *); + +-/* Although the RISC-V ABI does not specify that the dynamic section has +- to be read-only, it needs to be kept for ABI compatibility. */ +- +-#define DL_RO_DYN_SECTION 1 +- + #include_next + + #endif +-- +1.8.3.1 + diff --git a/ldconfig-avoid-leak-on-empty-paths-in-config-file.patch b/ldconfig-avoid-leak-on-empty-paths-in-config-file.patch new file mode 100644 index 0000000000000000000000000000000000000000..c415a470f20ad525d8eaf44e8025ef1804d888ad --- /dev/null +++ b/ldconfig-avoid-leak-on-empty-paths-in-config-file.patch @@ -0,0 +1,30 @@ +From b0234d79e7d82475d1666f25326ec045c045b3ed Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +Date: Tue, 3 Aug 2021 21:10:10 +0530 +Subject: [PATCH] ldconfig: avoid leak on empty paths in config file + +Reviewed-by: Arjun Shankar +--- + elf/ldconfig.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/elf/ldconfig.c b/elf/ldconfig.c +index 1037e8d..b889363 100644 +--- a/elf/ldconfig.c ++++ b/elf/ldconfig.c +@@ -503,7 +503,11 @@ add_dir_1 (const char *line, const char *from_file, int from_line) + entry->path[--i] = '\0'; + + if (i == 0) +- return; ++ { ++ free (entry->path); ++ free (entry); ++ return; ++ } + + char *path = entry->path; + if (opt_chroot != NULL) +-- +1.8.3.1 + diff --git a/linux-Fix-ancillary-64-bit-time-timestamp-conversion.patch b/linux-Fix-ancillary-64-bit-time-timestamp-conversion.patch new file mode 100644 index 0000000000000000000000000000000000000000..a4bf1ed7c677fa9a379638d38eca2e8b7fdc8ae5 --- /dev/null +++ b/linux-Fix-ancillary-64-bit-time-timestamp-conversion.patch @@ -0,0 +1,457 @@ +From e098446037da532d4a250efac9a813bc22f3669f Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Mon, 24 Jan 2022 08:55:53 -0300 +Subject: [PATCH] linux: Fix ancillary 64-bit time timestamp conversion (BZ + #28349, BZ#28350) + +The __convert_scm_timestamps only updates the control message last +pointer for SOL_SOCKET type, so if the message control buffer contains +multiple ancillary message types the converted timestamp one might +overwrite a valid message. + +The test checks if the extra ancillary space is correctly handled +by recvmsg/recvmmsg, where if there is no extra space for the 64-bit +time_t converted message the control buffer should be marked with +MSG_TRUNC. It also check if recvmsg/recvmmsg handle correctly multiple +ancillary data. + +Checked on x86_64-linux and on i686-linux-gnu on both 5.11 and +4.15 kernel. + +Co-authored-by: Fabian Vogt + +Reviewed-by: Florian Weimer + +(cherry picked from commit 8fba672472ae0055387e9315fc2eddfa6775ca79) +--- + NEWS | 3 + + sysdeps/unix/sysv/linux/Makefile | 3 + + .../unix/sysv/linux/convert_scm_timestamps.c | 14 +- + .../sysv/linux/tst-socket-timestamp-time64.c | 1 + + .../unix/sysv/linux/tst-socket-timestamp.c | 336 ++++++++++++++++++ + 5 files changed, 351 insertions(+), 6 deletions(-) + create mode 100644 sysdeps/unix/sysv/linux/tst-socket-timestamp-time64.c + create mode 100644 sysdeps/unix/sysv/linux/tst-socket-timestamp.c + +diff --git a/NEWS b/NEWS +index db50b2af..e5225e9f 100644 +--- a/NEWS ++++ b/NEWS +@@ -26,6 +26,9 @@ The following bugs are resolved with this release: + [12889] nptl: Fix race between pthread_kill and thread exit + [19193] nptl: pthread_kill, pthread_cancel should not fail after exit + [22542] CVE-2022-23219: Buffer overflow in sunrpc clnt_create for "unix" ++ [28349] libc: Segfault for ping -R on qemux86 caused by recvmsg() ++ [28350] libc: ping receives SIGABRT on lib32-qemux86-64 caused by ++ recvmsg() + + + Version 2.34 +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index 76ad0636..3399c874 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -262,6 +262,9 @@ sysdep_routines += cmsg_nxthdr + CFLAGS-recvmmsg.c = -fexceptions -fasynchronous-unwind-tables + CFLAGS-sendmmsg.c = -fexceptions -fasynchronous-unwind-tables + ++tests += tst-socket-timestamp ++tests-time64 += tst-socket-timestamp-time64 ++ + tests-special += $(objpfx)tst-socket-consts.out + $(objpfx)tst-socket-consts.out: ../sysdeps/unix/sysv/linux/tst-socket-consts.py + PYTHONPATH=../scripts \ +diff --git a/sysdeps/unix/sysv/linux/convert_scm_timestamps.c b/sysdeps/unix/sysv/linux/convert_scm_timestamps.c +index 00c934c4..5d3c4199 100644 +--- a/sysdeps/unix/sysv/linux/convert_scm_timestamps.c ++++ b/sysdeps/unix/sysv/linux/convert_scm_timestamps.c +@@ -54,6 +54,8 @@ __convert_scm_timestamps (struct msghdr *msg, socklen_t msgsize) + cmsg != NULL; + cmsg = CMSG_NXTHDR (msg, cmsg)) + { ++ last = cmsg; ++ + if (cmsg->cmsg_level != SOL_SOCKET) + continue; + +@@ -75,11 +77,9 @@ __convert_scm_timestamps (struct msghdr *msg, socklen_t msgsize) + tvts[1] = tmp[1]; + break; + } +- +- last = cmsg; + } + +- if (last == NULL || type == 0) ++ if (type == 0) + return; + + if (CMSG_SPACE (sizeof tvts) > msgsize - msg->msg_controllen) +@@ -88,10 +88,12 @@ __convert_scm_timestamps (struct msghdr *msg, socklen_t msgsize) + return; + } + ++ /* Zero memory for the new cmsghdr, so reading cmsg_len field ++ by CMSG_NXTHDR does not trigger UB. */ ++ memset (msg->msg_control + msg->msg_controllen, 0, ++ CMSG_SPACE (sizeof tvts)); + msg->msg_controllen += CMSG_SPACE (sizeof tvts); +- cmsg = CMSG_NXTHDR(msg, last); +- if (cmsg == NULL) +- return; ++ cmsg = CMSG_NXTHDR (msg, last); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = type; + cmsg->cmsg_len = CMSG_LEN (sizeof tvts); +diff --git a/sysdeps/unix/sysv/linux/tst-socket-timestamp-time64.c b/sysdeps/unix/sysv/linux/tst-socket-timestamp-time64.c +new file mode 100644 +index 00000000..ae424c2a +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-socket-timestamp-time64.c +@@ -0,0 +1 @@ ++#include "tst-socket-timestamp.c" +diff --git a/sysdeps/unix/sysv/linux/tst-socket-timestamp.c b/sysdeps/unix/sysv/linux/tst-socket-timestamp.c +new file mode 100644 +index 00000000..9c2e76f7 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-socket-timestamp.c +@@ -0,0 +1,336 @@ ++/* Check recvmsg/recvmmsg 64-bit timestamp support. ++ Copyright (C) 2022 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Some extra space added for ancillary data, it might be used to convert ++ 32-bit timestamp to 64-bit for _TIME_BITS=64. */ ++enum { slack_max_size = 64 }; ++static const int slack[] = { 0, 4, 8, 16, 32, slack_max_size }; ++ ++static bool support_64_timestamp; ++/* AF_INET socket and address used to receive data. */ ++static int srv; ++static struct sockaddr_in srv_addr; ++ ++static int ++do_sendto (const struct sockaddr_in *addr, int nmsgs) ++{ ++ int s = xsocket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); ++ xconnect (s, (const struct sockaddr *) addr, sizeof (*addr)); ++ ++ for (int i = 0; i < nmsgs; i++) ++ xsendto (s, &i, sizeof (i), 0, (const struct sockaddr *) addr, ++ sizeof (*addr)); ++ ++ xclose (s); ++ ++ return 0; ++} ++ ++static void ++do_recvmsg_slack_ancillary (bool use_multi_call, int s, void *cmsg, ++ size_t slack, size_t tsize, int exp_payload) ++{ ++ int payload; ++ struct iovec iov = ++ { ++ .iov_base = &payload, ++ .iov_len = sizeof (payload) ++ }; ++ size_t msg_controllen = CMSG_SPACE (tsize) + slack; ++ char *msg_control = cmsg - msg_controllen; ++ memset (msg_control, 0x55, msg_controllen); ++ struct mmsghdr mmhdr = ++ { ++ .msg_hdr = ++ { ++ .msg_name = NULL, ++ .msg_namelen = 0, ++ .msg_iov = &iov, ++ .msg_iovlen = 1, ++ .msg_control = msg_control, ++ .msg_controllen = msg_controllen ++ }, ++ }; ++ ++ int r; ++ if (use_multi_call) ++ { ++ r = recvmmsg (s, &mmhdr, 1, 0, NULL); ++ if (r >= 0) ++ r = mmhdr.msg_len; ++ } ++ else ++ r = recvmsg (s, &mmhdr.msg_hdr, 0); ++ TEST_COMPARE (r, sizeof (int)); ++ TEST_COMPARE (payload, exp_payload); ++ ++ if (cmsg == NULL) ++ return; ++ ++ /* A timestamp is expected if 32-bit timestamp are used (support in every ++ configuration) or if underlying kernel support 64-bit timestamps. ++ Otherwise recvmsg will need extra space do add the 64-bit timestamp. */ ++ bool exp_timestamp; ++ if (sizeof (time_t) == 4 || support_64_timestamp) ++ exp_timestamp = true; ++ else ++ exp_timestamp = slack >= CMSG_SPACE (tsize); ++ ++ bool timestamp = false; ++ for (struct cmsghdr *cmsg = CMSG_FIRSTHDR (&mmhdr.msg_hdr); ++ cmsg != NULL; ++ cmsg = CMSG_NXTHDR (&mmhdr.msg_hdr, cmsg)) ++ { ++ if (cmsg->cmsg_level != SOL_SOCKET) ++ continue; ++ if (cmsg->cmsg_type == SCM_TIMESTAMP ++ && cmsg->cmsg_len == CMSG_LEN (sizeof (struct timeval))) ++ { ++ struct timeval tv; ++ memcpy (&tv, CMSG_DATA (cmsg), sizeof (tv)); ++ if (test_verbose) ++ printf ("SCM_TIMESTAMP: {%jd, %jd}\n", (intmax_t)tv.tv_sec, ++ (intmax_t)tv.tv_usec); ++ timestamp = true; ++ } ++ else if (cmsg->cmsg_type == SCM_TIMESTAMPNS ++ && cmsg->cmsg_len == CMSG_LEN (sizeof (struct timespec))) ++ { ++ struct timespec ts; ++ memcpy (&ts, CMSG_DATA (cmsg), sizeof (ts)); ++ if (test_verbose) ++ printf ("SCM_TIMESTAMPNS: {%jd, %jd}\n", (intmax_t)ts.tv_sec, ++ (intmax_t)ts.tv_nsec); ++ timestamp = true; ++ } ++ } ++ ++ TEST_COMPARE (timestamp, exp_timestamp); ++} ++ ++/* Check if the extra ancillary space is correctly handled by recvmsg and ++ recvmmsg with different extra space for the ancillaty buffer. */ ++static void ++do_test_slack_space (void) ++{ ++ /* Setup the ancillary data buffer with an extra page with PROT_NONE to ++ check the possible timestamp conversion on some systems. */ ++ struct support_next_to_fault nf = ++ support_next_to_fault_allocate (slack_max_size); ++ void *msgbuf = nf.buffer + slack_max_size; ++ ++ /* Enable the timestamp using struct timeval precision. */ ++ { ++ int r = setsockopt (srv, SOL_SOCKET, SO_TIMESTAMP, &(int){1}, ++ sizeof (int)); ++ TEST_VERIFY_EXIT (r != -1); ++ } ++ /* Check recvmsg. */ ++ do_sendto (&srv_addr, array_length (slack)); ++ for (int s = 0; s < array_length (slack); s++) ++ { ++ memset (nf.buffer, 0x55, nf.length); ++ do_recvmsg_slack_ancillary (false, srv, msgbuf, slack[s], ++ sizeof (struct timeval), s); ++ } ++ /* Check recvmmsg. */ ++ do_sendto (&srv_addr, array_length (slack)); ++ for (int s = 0; s < array_length (slack); s++) ++ { ++ memset (nf.buffer, 0x55, nf.length); ++ do_recvmsg_slack_ancillary (true, srv, msgbuf, slack[s], ++ sizeof (struct timeval), s); ++ } ++ ++ /* Now enable timestamp using a higher precision, it overwrites the previous ++ precision. */ ++ { ++ int r = setsockopt (srv, SOL_SOCKET, SO_TIMESTAMPNS, &(int){1}, ++ sizeof (int)); ++ TEST_VERIFY_EXIT (r != -1); ++ } ++ /* Check recvmsg. */ ++ do_sendto (&srv_addr, array_length (slack)); ++ for (int s = 0; s < array_length (slack); s++) ++ do_recvmsg_slack_ancillary (false, srv, msgbuf, slack[s], ++ sizeof (struct timespec), s); ++ /* Check recvmmsg. */ ++ do_sendto (&srv_addr, array_length (slack)); ++ for (int s = 0; s < array_length (slack); s++) ++ do_recvmsg_slack_ancillary (true, srv, msgbuf, slack[s], ++ sizeof (struct timespec), s); ++ ++ support_next_to_fault_free (&nf); ++} ++ ++/* Check if the converted 64-bit timestamp is correctly appended when there ++ are multiple ancillary messages. */ ++static void ++do_recvmsg_multiple_ancillary (bool use_multi_call, int s, void *cmsg, ++ size_t cmsgsize, int exp_msg) ++{ ++ int msg; ++ struct iovec iov = ++ { ++ .iov_base = &msg, ++ .iov_len = sizeof (msg) ++ }; ++ size_t msgs = cmsgsize; ++ struct mmsghdr mmhdr = ++ { ++ .msg_hdr = ++ { ++ .msg_name = NULL, ++ .msg_namelen = 0, ++ .msg_iov = &iov, ++ .msg_iovlen = 1, ++ .msg_controllen = msgs, ++ .msg_control = cmsg, ++ }, ++ }; ++ ++ int r; ++ if (use_multi_call) ++ { ++ r = recvmmsg (s, &mmhdr, 1, 0, NULL); ++ if (r >= 0) ++ r = mmhdr.msg_len; ++ } ++ else ++ r = recvmsg (s, &mmhdr.msg_hdr, 0); ++ TEST_COMPARE (r, sizeof (int)); ++ TEST_COMPARE (msg, exp_msg); ++ ++ if (cmsg == NULL) ++ return; ++ ++ bool timestamp = false; ++ bool origdstaddr = false; ++ for (struct cmsghdr *cmsg = CMSG_FIRSTHDR (&mmhdr.msg_hdr); ++ cmsg != NULL; ++ cmsg = CMSG_NXTHDR (&mmhdr.msg_hdr, cmsg)) ++ { ++ if (cmsg->cmsg_level == SOL_IP ++ && cmsg->cmsg_type == IP_ORIGDSTADDR ++ && cmsg->cmsg_len >= CMSG_LEN (sizeof (struct sockaddr_in))) ++ { ++ struct sockaddr_in sa; ++ memcpy (&sa, CMSG_DATA (cmsg), sizeof (sa)); ++ if (test_verbose) ++ { ++ char str[INET_ADDRSTRLEN]; ++ inet_ntop (AF_INET, &sa.sin_addr, str, INET_ADDRSTRLEN); ++ printf ("IP_ORIGDSTADDR: %s:%d\n", str, ntohs (sa.sin_port)); ++ } ++ origdstaddr = sa.sin_addr.s_addr == srv_addr.sin_addr.s_addr ++ && sa.sin_port == srv_addr.sin_port; ++ } ++ if (cmsg->cmsg_level == SOL_SOCKET ++ && cmsg->cmsg_type == SCM_TIMESTAMP ++ && cmsg->cmsg_len >= CMSG_LEN (sizeof (struct timeval))) ++ { ++ struct timeval tv; ++ memcpy (&tv, CMSG_DATA (cmsg), sizeof (tv)); ++ if (test_verbose) ++ printf ("SCM_TIMESTAMP: {%jd, %jd}\n", (intmax_t)tv.tv_sec, ++ (intmax_t)tv.tv_usec); ++ timestamp = true; ++ } ++ } ++ ++ TEST_COMPARE (timestamp, true); ++ TEST_COMPARE (origdstaddr, true); ++} ++ ++static void ++do_test_multiple_ancillary (void) ++{ ++ { ++ int r = setsockopt (srv, SOL_SOCKET, SO_TIMESTAMP, &(int){1}, ++ sizeof (int)); ++ TEST_VERIFY_EXIT (r != -1); ++ } ++ { ++ int r = setsockopt (srv, IPPROTO_IP, IP_RECVORIGDSTADDR, &(int){1}, ++ sizeof (int)); ++ TEST_VERIFY_EXIT (r != -1); ++ } ++ ++ /* Enougth data for default SO_TIMESTAMP, the IP_RECVORIGDSTADDR, and the ++ extra 64-bit SO_TIMESTAMP. */ ++ enum { msgbuflen = CMSG_SPACE (2 * sizeof (uint64_t)) ++ + CMSG_SPACE (sizeof (struct sockaddr_in)) ++ + CMSG_SPACE (2 * sizeof (uint64_t)) }; ++ char msgbuf[msgbuflen]; ++ ++ enum { nmsgs = 8 }; ++ /* Check recvmsg. */ ++ do_sendto (&srv_addr, nmsgs); ++ for (int s = 0; s < nmsgs; s++) ++ do_recvmsg_multiple_ancillary (false, srv, msgbuf, msgbuflen, s); ++ /* Check recvmmsg. */ ++ do_sendto (&srv_addr, nmsgs); ++ for (int s = 0; s < nmsgs; s++) ++ do_recvmsg_multiple_ancillary (true, srv, msgbuf, msgbuflen, s); ++} ++ ++static int ++do_test (void) ++{ ++ srv = xsocket (AF_INET, SOCK_DGRAM, 0); ++ srv_addr = (struct sockaddr_in) { ++ .sin_family = AF_INET, ++ .sin_addr = {.s_addr = htonl (INADDR_LOOPBACK) }, ++ }; ++ xbind (srv, (struct sockaddr *) &srv_addr, sizeof (srv_addr)); ++ { ++ socklen_t sa_len = sizeof (srv_addr); ++ xgetsockname (srv, (struct sockaddr *) &srv_addr, &sa_len); ++ TEST_VERIFY (sa_len == sizeof (srv_addr)); ++ } ++ ++ TEST_COMPARE (recvmsg (-1, NULL, 0), -1); ++ TEST_COMPARE (errno, EBADF); ++ TEST_COMPARE (recvmmsg (-1, NULL, 0, 0, NULL), -1); ++ TEST_COMPARE (errno, EBADF); ++ ++ /* If underlying kernel does not support */ ++ support_64_timestamp = support_socket_so_timestamp_time64 (srv); ++ ++ do_test_slack_space (); ++ do_test_multiple_ancillary (); ++ ++ xclose (srv); ++ ++ return 0; ++} ++ ++#include +-- +2.27.0 + diff --git a/linux-Fix-missing-__convert_scm_timestamps-BZ-28860.patch b/linux-Fix-missing-__convert_scm_timestamps-BZ-28860.patch new file mode 100644 index 0000000000000000000000000000000000000000..bcfed33faebb5216e8560d71790228bf07fd7a63 --- /dev/null +++ b/linux-Fix-missing-__convert_scm_timestamps-BZ-28860.patch @@ -0,0 +1,37 @@ +From 0351c75c5f94134fcec0e778e8cf86d149f8bbfb Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Thu, 3 Feb 2022 16:52:52 -0300 +Subject: [PATCH] linux: Fix missing __convert_scm_timestamps (BZ #28860) + +Commit 948ce73b31 made recvmsg/recvmmsg to always call +__convert_scm_timestamps for 64 bit time_t symbol, so adjust it to +always build it for __TIMESIZE != 64. + +It fixes build for architecture with 32 bit time_t support when +configured with minimum kernel of 5.1. + +(cherry-picked from 798d716df71fb23dc89d1d5dba1fc26a1b5c0024) +--- + sysdeps/unix/sysv/linux/convert_scm_timestamps.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/sysdeps/unix/sysv/linux/convert_scm_timestamps.c b/sysdeps/unix/sysv/linux/convert_scm_timestamps.c +index 5d3c4199e0..953ce97bd2 100644 +--- a/sysdeps/unix/sysv/linux/convert_scm_timestamps.c ++++ b/sysdeps/unix/sysv/linux/convert_scm_timestamps.c +@@ -16,9 +16,10 @@ + License along with the GNU C Library; if not, see + . */ + +-#include ++#include ++#include + +-#ifndef __ASSUME_TIME64_SYSCALLS ++#if __TIMESIZE != 64 + # include + # include + # include +-- +2.27.0 + diff --git a/linux-Revert-the-use-of-sched_getaffinity-on-get_npr.patch b/linux-Revert-the-use-of-sched_getaffinity-on-get_npr.patch new file mode 100644 index 0000000000000000000000000000000000000000..17a7a5ce7c3aa2d8f8168c0d7c71f9b99323452c --- /dev/null +++ b/linux-Revert-the-use-of-sched_getaffinity-on-get_npr.patch @@ -0,0 +1,206 @@ +From 342298278eabc75baabcaced110a11a02c3d3580 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Mon, 6 Sep 2021 14:19:51 -0300 +Subject: [PATCH] linux: Revert the use of sched_getaffinity on get_nproc (BZ + #28310) + +The use of sched_getaffinity on get_nproc and +sysconf (_SC_NPROCESSORS_ONLN) done in 903bc7dcc2acafc40 (BZ #27645) +breaks the top command in common hypervisor configurations and also +other monitoring tools. + +The main issue using sched_getaffinity changed the symbols semantic +from system-wide scope of online CPUs to per-process one (which can +be changed with kernel cpusets or book parameters in VM). + +This patch reverts mostly of the 903bc7dcc2acafc40, with the +exceptions: + + * No more cached values and atomic updates, since they are inherent + racy. + + * No /proc/cpuinfo fallback, since /proc/stat is already used and + it would require to revert more arch-specific code. + + * The alloca is replace with a static buffer of 1024 bytes. + +So the implementation first consult the sysfs, and fallbacks to procfs. + +Checked on x86_64-linux-gnu. + +Reviewed-by: Florian Weimer +--- + sysdeps/unix/sysv/linux/getsysstats.c | 139 ++++++++++++++++++++++++++++++++-- + 1 file changed, 134 insertions(+), 5 deletions(-) + +diff --git a/sysdeps/unix/sysv/linux/getsysstats.c b/sysdeps/unix/sysv/linux/getsysstats.c +index 1e3d886..15ad91c 100644 +--- a/sysdeps/unix/sysv/linux/getsysstats.c ++++ b/sysdeps/unix/sysv/linux/getsysstats.c +@@ -17,6 +17,8 @@ + . */ + + #include ++#include ++#include + #include + #include + #include +@@ -29,7 +31,7 @@ + #include + + int +-__get_nprocs (void) ++__get_nprocs_sched (void) + { + enum + { +@@ -52,14 +54,141 @@ __get_nprocs (void) + atomics are needed). */ + return 2; + } +-libc_hidden_def (__get_nprocs) +-weak_alias (__get_nprocs, get_nprocs) ++ ++static char * ++next_line (int fd, char *const buffer, char **cp, char **re, ++ char *const buffer_end) ++{ ++ char *res = *cp; ++ char *nl = memchr (*cp, '\n', *re - *cp); ++ if (nl == NULL) ++ { ++ if (*cp != buffer) ++ { ++ if (*re == buffer_end) ++ { ++ memmove (buffer, *cp, *re - *cp); ++ *re = buffer + (*re - *cp); ++ *cp = buffer; ++ ++ ssize_t n = __read_nocancel (fd, *re, buffer_end - *re); ++ if (n < 0) ++ return NULL; ++ ++ *re += n; ++ ++ nl = memchr (*cp, '\n', *re - *cp); ++ while (nl == NULL && *re == buffer_end) ++ { ++ /* Truncate too long lines. */ ++ *re = buffer + 3 * (buffer_end - buffer) / 4; ++ n = __read_nocancel (fd, *re, buffer_end - *re); ++ if (n < 0) ++ return NULL; ++ ++ nl = memchr (*re, '\n', n); ++ **re = '\n'; ++ *re += n; ++ } ++ } ++ else ++ nl = memchr (*cp, '\n', *re - *cp); ++ ++ res = *cp; ++ } ++ ++ if (nl == NULL) ++ nl = *re - 1; ++ } ++ ++ *cp = nl + 1; ++ assert (*cp <= *re); ++ ++ return res == *re ? NULL : res; ++} ++ + + int +-__get_nprocs_sched (void) ++__get_nprocs (void) + { +- return __get_nprocs (); ++ enum { buffer_size = 1024 }; ++ char buffer[buffer_size]; ++ char *buffer_end = buffer + buffer_size; ++ char *cp = buffer_end; ++ char *re = buffer_end; ++ ++ const int flags = O_RDONLY | O_CLOEXEC; ++ /* This file contains comma-separated ranges. */ ++ int fd = __open_nocancel ("/sys/devices/system/cpu/online", flags); ++ char *l; ++ int result = 0; ++ if (fd != -1) ++ { ++ l = next_line (fd, buffer, &cp, &re, buffer_end); ++ if (l != NULL) ++ do ++ { ++ char *endp; ++ unsigned long int n = strtoul (l, &endp, 10); ++ if (l == endp) ++ { ++ result = 0; ++ break; ++ } ++ ++ unsigned long int m = n; ++ if (*endp == '-') ++ { ++ l = endp + 1; ++ m = strtoul (l, &endp, 10); ++ if (l == endp) ++ { ++ result = 0; ++ break; ++ } ++ } ++ ++ result += m - n + 1; ++ ++ l = endp; ++ if (l < re && *l == ',') ++ ++l; ++ } ++ while (l < re && *l != '\n'); ++ ++ __close_nocancel_nostatus (fd); ++ ++ if (result > 0) ++ return result; ++ } ++ ++ cp = buffer_end; ++ re = buffer_end; ++ ++ /* Default to an SMP system in case we cannot obtain an accurate ++ number. */ ++ result = 2; ++ ++ fd = __open_nocancel ("/proc/stat", flags); ++ if (fd != -1) ++ { ++ result = 0; ++ ++ while ((l = next_line (fd, buffer, &cp, &re, buffer_end)) != NULL) ++ /* The current format of /proc/stat has all the cpu* entries ++ at the front. We assume here that stays this way. */ ++ if (strncmp (l, "cpu", 3) != 0) ++ break; ++ else if (isdigit (l[3])) ++ ++result; ++ ++ __close_nocancel_nostatus (fd); ++ } ++ ++ return result; + } ++libc_hidden_def (__get_nprocs) ++weak_alias (__get_nprocs, get_nprocs) + + + /* On some architectures it is possible to distinguish between configured +-- +1.8.3.1 + diff --git a/linux-Simplify-get_nprocs.patch b/linux-Simplify-get_nprocs.patch new file mode 100644 index 0000000000000000000000000000000000000000..55c49b227a6d74218bcbb88e8017cfd8eb2b00b5 --- /dev/null +++ b/linux-Simplify-get_nprocs.patch @@ -0,0 +1,216 @@ +From cda99af14e82b4bb6abaecd717ebe3b57c0aa534 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Mon, 6 Sep 2021 12:28:24 -0300 +Subject: [PATCH] linux: Simplify get_nprocs + +This patch simplifies the memory allocation code and uses the sched +routines instead of reimplement it. This still uses a stack +allocation buffer, so it can be used on malloc initialization code. + +Linux currently supports at maximum of 4096 cpus for most architectures: + +$ find -iname Kconfig | xargs git grep -A10 -w NR_CPUS | grep -w range +arch/alpha/Kconfig- range 2 32 +arch/arc/Kconfig- range 2 4096 +arch/arm/Kconfig- range 2 16 if DEBUG_KMAP_LOCAL +arch/arm/Kconfig- range 2 32 if !DEBUG_KMAP_LOCAL +arch/arm64/Kconfig- range 2 4096 +arch/csky/Kconfig- range 2 32 +arch/hexagon/Kconfig- range 2 6 if SMP +arch/ia64/Kconfig- range 2 4096 +arch/mips/Kconfig- range 2 256 +arch/openrisc/Kconfig- range 2 32 +arch/parisc/Kconfig- range 2 32 +arch/riscv/Kconfig- range 2 32 +arch/s390/Kconfig- range 2 512 +arch/sh/Kconfig- range 2 32 +arch/sparc/Kconfig- range 2 32 if SPARC32 +arch/sparc/Kconfig- range 2 4096 if SPARC64 +arch/um/Kconfig- range 1 1 +arch/x86/Kconfig-# [NR_CPUS_RANGE_BEGIN ... NR_CPUS_RANGE_END] range. +arch/x86/Kconfig- range NR_CPUS_RANGE_BEGIN NR_CPUS_RANGE_END +arch/xtensa/Kconfig- range 2 32 + +With x86 supporting 8192: + +arch/x86/Kconfig + 976 config NR_CPUS_RANGE_END + 977 int + 978 depends on X86_64 + 979 default 8192 if SMP && CPUMASK_OFFSTACK + 980 default 512 if SMP && !CPUMASK_OFFSTACK + 981 default 1 if !SMP + +So using a maximum of 32k cpu should cover all cases (and I would +expect once we start to have many more CPUs that Linux would provide +a more straightforward way to query for such information). + +A test is added to check if sched_getaffinity can successfully return +with large buffers. + +Checked on x86_64-linux-gnu and i686-linux-gnu. + +Reviewed-by: Florian Weimer +(cherry picked from commit 33099d72e41cf8a129b362e9709eb2be9372d844) +--- + posix/Makefile | 3 +- + posix/tst-sched_getaffinity.c | 48 +++++++++++++++++++++++++ + sysdeps/unix/sysv/linux/getsysstats.c | 68 ++++++++++------------------------- + 3 files changed, 68 insertions(+), 51 deletions(-) + create mode 100644 posix/tst-sched_getaffinity.c + +diff --git a/posix/Makefile b/posix/Makefile +index 059efb3..09460a2 100644 +--- a/posix/Makefile ++++ b/posix/Makefile +@@ -107,7 +107,8 @@ tests := test-errno tstgetopt testfnm runtests runptests \ + tst-sysconf-empty-chroot tst-glob_symlinks tst-fexecve \ + tst-glob-tilde test-ssize-max tst-spawn4 bug-regex37 \ + bug-regex38 tst-regcomp-truncated tst-spawn-chdir \ +- tst-wordexp-nocmd tst-execveat tst-spawn5 ++ tst-wordexp-nocmd tst-execveat tst-spawn5 \ ++ tst-sched_getaffinity + + # Test for the glob symbol version that was replaced in glibc 2.27. + ifeq ($(have-GLIBC_2.26)$(build-shared),yesyes) +diff --git a/posix/tst-sched_getaffinity.c b/posix/tst-sched_getaffinity.c +new file mode 100644 +index 0000000..db9d517 +--- /dev/null ++++ b/posix/tst-sched_getaffinity.c +@@ -0,0 +1,48 @@ ++/* Tests for sched_getaffinity with large buffers. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++ ++/* NB: this test may fail on system with more than 32k cpus. */ ++ ++static int ++do_test (void) ++{ ++ /* The values are larger than the default cpu_set_t. */ ++ const int bufsize[] = { 1<<11, 1<<12, 1<<13, 1<<14, 1<<15, 1<<16, 1<<17 }; ++ int cpucount[array_length (bufsize)]; ++ ++ for (int i = 0; i < array_length (bufsize); i++) ++ { ++ cpu_set_t *cpuset = CPU_ALLOC (bufsize[i]); ++ TEST_VERIFY (cpuset != NULL); ++ size_t size = CPU_ALLOC_SIZE (bufsize[i]); ++ TEST_COMPARE (sched_getaffinity (0, size, cpuset), 0); ++ cpucount[i] = CPU_COUNT_S (size, cpuset); ++ CPU_FREE (cpuset); ++ } ++ ++ for (int i = 0; i < array_length (cpucount) - 1; i++) ++ TEST_COMPARE (cpucount[i], cpucount[i + 1]); ++ ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/unix/sysv/linux/getsysstats.c b/sysdeps/unix/sysv/linux/getsysstats.c +index 120ce1b..61d20e7 100644 +--- a/sysdeps/unix/sysv/linux/getsysstats.c ++++ b/sysdeps/unix/sysv/linux/getsysstats.c +@@ -29,61 +29,29 @@ + #include + #include + +-/* Compute the population count of the entire array. */ +-static int +-__get_nprocs_count (const unsigned long int *array, size_t length) +-{ +- int count = 0; +- for (size_t i = 0; i < length; ++i) +- if (__builtin_add_overflow (count, __builtin_popcountl (array[i]), +- &count)) +- return INT_MAX; +- return count; +-} +- +-/* __get_nprocs with a large buffer. */ +-static int +-__get_nprocs_large (void) +-{ +- /* This code cannot use scratch_buffer because it is used during +- malloc initialization. */ +- size_t pagesize = GLRO (dl_pagesize); +- unsigned long int *page = __mmap (0, pagesize, PROT_READ | PROT_WRITE, +- MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); +- if (page == MAP_FAILED) +- return 2; +- int r = INTERNAL_SYSCALL_CALL (sched_getaffinity, 0, pagesize, page); +- int count; +- if (r > 0) +- count = __get_nprocs_count (page, pagesize / sizeof (unsigned long int)); +- else if (r == -EINVAL) +- /* One page is still not enough to store the bits. A more-or-less +- arbitrary value. This assumes t hat such large systems never +- happen in practice. */ +- count = GLRO (dl_pagesize) * CHAR_BIT; +- else +- count = 2; +- __munmap (page, GLRO (dl_pagesize)); +- return count; +-} +- + int + __get_nprocs (void) + { +- /* Fast path for most systems. The kernel expects a buffer size +- that is a multiple of 8. */ +- unsigned long int small_buffer[1024 / CHAR_BIT / sizeof (unsigned long int)]; +- int r = INTERNAL_SYSCALL_CALL (sched_getaffinity, 0, +- sizeof (small_buffer), small_buffer); ++ enum ++ { ++ max_num_cpus = 32768, ++ cpu_bits_size = CPU_ALLOC_SIZE (32768) ++ }; ++ ++ /* This cannot use malloc because it is used on malloc initialization. */ ++ __cpu_mask cpu_bits[cpu_bits_size / sizeof (__cpu_mask)]; ++ int r = INTERNAL_SYSCALL_CALL (sched_getaffinity, 0, cpu_bits_size, ++ cpu_bits); + if (r > 0) +- return __get_nprocs_count (small_buffer, r / sizeof (unsigned long int)); ++ return CPU_COUNT_S (cpu_bits_size, (cpu_set_t*) cpu_bits); + else if (r == -EINVAL) +- /* The kernel requests a larger buffer to store the data. */ +- return __get_nprocs_large (); +- else +- /* Some other error. 2 is conservative (not a uniprocessor +- system, so atomics are needed). */ +- return 2; ++ /* The input buffer is still not enough to store the number of cpus. This ++ is an arbitrary values assuming such systems should be rare and there ++ is no offline cpus. */ ++ return max_num_cpus; ++ /* Some other error. 2 is conservative (not a uniprocessor system, so ++ atomics are needed). */ ++ return 2; + } + libc_hidden_def (__get_nprocs) + weak_alias (__get_nprocs, get_nprocs) +-- +1.8.3.1 + diff --git a/linux-Use-proc-stat-fallback-for-__get_nprocs_conf-B.patch b/linux-Use-proc-stat-fallback-for-__get_nprocs_conf-B.patch new file mode 100644 index 0000000000000000000000000000000000000000..57c9aa205383c8ed52b0a4b09274e198f5379cec --- /dev/null +++ b/linux-Use-proc-stat-fallback-for-__get_nprocs_conf-B.patch @@ -0,0 +1,102 @@ +From 137ed5ac440a4d3cf4178ce97f349b349a9c2c66 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Thu, 25 Nov 2021 09:12:00 -0300 +Subject: [PATCH] linux: Use /proc/stat fallback for __get_nprocs_conf (BZ + #28624) + +The /proc/statm fallback was removed by f13fb81ad3159 if sysfs is +not available, reinstate it. + +Checked on x86_64-linux-gnu. +--- + sysdeps/unix/sysv/linux/getsysstats.c | 60 ++++++++++++++++++++--------------- + 1 file changed, 35 insertions(+), 25 deletions(-) + +diff --git a/sysdeps/unix/sysv/linux/getsysstats.c b/sysdeps/unix/sysv/linux/getsysstats.c +index 15ad91c..d376f05 100644 +--- a/sysdeps/unix/sysv/linux/getsysstats.c ++++ b/sysdeps/unix/sysv/linux/getsysstats.c +@@ -107,6 +107,37 @@ next_line (int fd, char *const buffer, char **cp, char **re, + return res == *re ? NULL : res; + } + ++static int ++get_nproc_stat (char *buffer, size_t buffer_size) ++{ ++ char *buffer_end = buffer + buffer_size; ++ char *cp = buffer_end; ++ char *re = buffer_end; ++ ++ /* Default to an SMP system in case we cannot obtain an accurate ++ number. */ ++ int result = 2; ++ ++ const int flags = O_RDONLY | O_CLOEXEC; ++ int fd = __open_nocancel ("/proc/stat", flags); ++ if (fd != -1) ++ { ++ result = 0; ++ ++ char *l; ++ while ((l = next_line (fd, buffer, &cp, &re, buffer_end)) != NULL) ++ /* The current format of /proc/stat has all the cpu* entries ++ at the front. We assume here that stays this way. */ ++ if (strncmp (l, "cpu", 3) != 0) ++ break; ++ else if (isdigit (l[3])) ++ ++result; ++ ++ __close_nocancel_nostatus (fd); ++ } ++ ++ return result; ++} + + int + __get_nprocs (void) +@@ -162,30 +193,7 @@ __get_nprocs (void) + return result; + } + +- cp = buffer_end; +- re = buffer_end; +- +- /* Default to an SMP system in case we cannot obtain an accurate +- number. */ +- result = 2; +- +- fd = __open_nocancel ("/proc/stat", flags); +- if (fd != -1) +- { +- result = 0; +- +- while ((l = next_line (fd, buffer, &cp, &re, buffer_end)) != NULL) +- /* The current format of /proc/stat has all the cpu* entries +- at the front. We assume here that stays this way. */ +- if (strncmp (l, "cpu", 3) != 0) +- break; +- else if (isdigit (l[3])) +- ++result; +- +- __close_nocancel_nostatus (fd); +- } +- +- return result; ++ return get_nproc_stat (buffer, buffer_size); + } + libc_hidden_def (__get_nprocs) + weak_alias (__get_nprocs, get_nprocs) +@@ -219,7 +227,9 @@ __get_nprocs_conf (void) + return count; + } + +- return 1; ++ enum { buffer_size = 1024 }; ++ char buffer[buffer_size]; ++ return get_nproc_stat (buffer, buffer_size); + } + libc_hidden_def (__get_nprocs_conf) + weak_alias (__get_nprocs_conf, get_nprocs_conf) +-- +1.8.3.1 + diff --git a/linux-__get_nprocs_sched-do-not-feed-CPU_COUNT_S-wit.patch b/linux-__get_nprocs_sched-do-not-feed-CPU_COUNT_S-wit.patch new file mode 100644 index 0000000000000000000000000000000000000000..0bf8f6d588959340370bc8550602f9fc7acae0a8 --- /dev/null +++ b/linux-__get_nprocs_sched-do-not-feed-CPU_COUNT_S-wit.patch @@ -0,0 +1,30 @@ +From 97ba273b505763325efd802dc3a9562dbba79579 Mon Sep 17 00:00:00 2001 +From: Gleb Fotengauer-Malinovskiy +Date: Tue, 1 Feb 2022 22:39:02 +0000 +Subject: [PATCH] linux: __get_nprocs_sched: do not feed CPU_COUNT_S with + garbage [BZ #28850] + +Pass the actual number of bytes returned by the kernel. + +Fixes: 33099d72e41c ("linux: Simplify get_nprocs") +Reviewed-by: Dmitry V. Levin +--- + sysdeps/unix/sysv/linux/getsysstats.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sysdeps/unix/sysv/linux/getsysstats.c b/sysdeps/unix/sysv/linux/getsysstats.c +index 4798cc3..c98c8ce 100644 +--- a/sysdeps/unix/sysv/linux/getsysstats.c ++++ b/sysdeps/unix/sysv/linux/getsysstats.c +@@ -44,7 +44,7 @@ __get_nprocs_sched (void) + int r = INTERNAL_SYSCALL_CALL (sched_getaffinity, 0, cpu_bits_size, + cpu_bits); + if (r > 0) +- return CPU_COUNT_S (cpu_bits_size, (cpu_set_t*) cpu_bits); ++ return CPU_COUNT_S (r, (cpu_set_t*) cpu_bits); + else if (r == -EINVAL) + /* The input buffer is still not enough to store the number of cpus. This + is an arbitrary values assuming such systems should be rare and there +-- +1.8.3.1 + diff --git a/linux-fix-accuracy-of-get_nprocs-and-get_nprocs_conf.patch b/linux-fix-accuracy-of-get_nprocs-and-get_nprocs_conf.patch new file mode 100644 index 0000000000000000000000000000000000000000..d16fa755a8b3ec37410850233f33ee7abcb64ea4 --- /dev/null +++ b/linux-fix-accuracy-of-get_nprocs-and-get_nprocs_conf.patch @@ -0,0 +1,212 @@ +From 007e054d786be340699c634e3a3b30ab1fde1a7a Mon Sep 17 00:00:00 2001 +From: "Dmitry V. Levin" +Date: Sat, 5 Feb 2022 08:00:00 +0000 +Subject: [PATCH] linux: fix accuracy of get_nprocs and get_nprocs_conf [BZ + #28865] + +get_nprocs() and get_nprocs_conf() use various methods to obtain an +accurate number of processors. Re-introduce __get_nprocs_sched() as +a source of information, and fix the order in which these methods are +used to return the most accurate information. The primary source of +information used in both functions remains unchanged. + +This also changes __get_nprocs_sched() error return value from 2 to 0, +but all its users are already prepared to handle that. + +Old fallback order: + get_nprocs: + /sys/devices/system/cpu/online -> /proc/stat -> 2 + get_nprocs_conf: + /sys/devices/system/cpu/ -> /proc/stat -> 2 + +New fallback order: + get_nprocs: + /sys/devices/system/cpu/online -> /proc/stat -> sched_getaffinity -> 2 + get_nprocs_conf: + /sys/devices/system/cpu/ -> /proc/stat -> sched_getaffinity -> 2 + +Fixes: 342298278e ("linux: Revert the use of sched_getaffinity on get_nproc") +Closes: BZ #28865 +Reviewed-by: Adhemerval Zanella + +(cherry picked from commit e1d32b836410767270a3adf1f82b1a47e6e4cd51) +--- + NEWS | 2 + + sysdeps/unix/sysv/linux/getsysstats.c | 94 ++++++++++++++++++--------- + 2 files changed, 65 insertions(+), 31 deletions(-) + +diff --git a/NEWS b/NEWS +index 87c9517e1a..aef051122e 100644 +--- a/NEWS ++++ b/NEWS +@@ -29,6 +29,8 @@ The following bugs are resolved with this release: + [28349] libc: Segfault for ping -R on qemux86 caused by recvmsg() + [28350] libc: ping receives SIGABRT on lib32-qemux86-64 caused by + recvmsg() ++ [28865] linux: _SC_NPROCESSORS_CONF and _SC_NPROCESSORS_ONLN are inaccurate ++ without /sys and /proc + + + Version 2.34 +diff --git a/sysdeps/unix/sysv/linux/getsysstats.c b/sysdeps/unix/sysv/linux/getsysstats.c +index 7babd947aa..327802b14c 100644 +--- a/sysdeps/unix/sysv/linux/getsysstats.c ++++ b/sysdeps/unix/sysv/linux/getsysstats.c +@@ -51,9 +51,8 @@ __get_nprocs_sched (void) + is an arbitrary values assuming such systems should be rare and there + is no offline cpus. */ + return max_num_cpus; +- /* Some other error. 2 is conservative (not a uniprocessor system, so +- atomics are needed). */ +- return 2; ++ /* Some other error. */ ++ return 0; + } + + static char * +@@ -109,22 +108,19 @@ next_line (int fd, char *const buffer, char **cp, char **re, + } + + static int +-get_nproc_stat (char *buffer, size_t buffer_size) ++get_nproc_stat (void) + { ++ enum { buffer_size = 1024 }; ++ char buffer[buffer_size]; + char *buffer_end = buffer + buffer_size; + char *cp = buffer_end; + char *re = buffer_end; +- +- /* Default to an SMP system in case we cannot obtain an accurate +- number. */ +- int result = 2; ++ int result = 0; + + const int flags = O_RDONLY | O_CLOEXEC; + int fd = __open_nocancel ("/proc/stat", flags); + if (fd != -1) + { +- result = 0; +- + char *l; + while ((l = next_line (fd, buffer, &cp, &re, buffer_end)) != NULL) + /* The current format of /proc/stat has all the cpu* entries +@@ -140,8 +136,8 @@ get_nproc_stat (char *buffer, size_t buffer_size) + return result; + } + +-int +-__get_nprocs (void) ++static int ++get_nprocs_cpu_online (void) + { + enum { buffer_size = 1024 }; + char buffer[buffer_size]; +@@ -180,7 +176,8 @@ __get_nprocs (void) + } + } + +- result += m - n + 1; ++ if (m >= n) ++ result += m - n + 1; + + l = endp; + if (l < re && *l == ',') +@@ -189,28 +186,18 @@ __get_nprocs (void) + while (l < re && *l != '\n'); + + __close_nocancel_nostatus (fd); +- +- if (result > 0) +- return result; + } + +- return get_nproc_stat (buffer, buffer_size); ++ return result; + } +-libc_hidden_def (__get_nprocs) +-weak_alias (__get_nprocs, get_nprocs) +- + +-/* On some architectures it is possible to distinguish between configured +- and active cpus. */ +-int +-__get_nprocs_conf (void) ++static int ++get_nprocs_cpu (void) + { +- /* Try to use the sysfs filesystem. It has actual information about +- online processors. */ ++ int count = 0; + DIR *dir = __opendir ("/sys/devices/system/cpu"); + if (dir != NULL) + { +- int count = 0; + struct dirent64 *d; + + while ((d = __readdir64 (dir)) != NULL) +@@ -225,12 +212,57 @@ __get_nprocs_conf (void) + + __closedir (dir); + +- return count; + } ++ return count; ++} + +- enum { buffer_size = 1024 }; +- char buffer[buffer_size]; +- return get_nproc_stat (buffer, buffer_size); ++static int ++get_nprocs_fallback (void) ++{ ++ int result; ++ ++ /* Try /proc/stat first. */ ++ result = get_nproc_stat (); ++ if (result != 0) ++ return result; ++ ++ /* Try sched_getaffinity. */ ++ result = __get_nprocs_sched (); ++ if (result != 0) ++ return result; ++ ++ /* We failed to obtain an accurate number. Be conservative: return ++ the smallest number meaning that this is not a uniprocessor system, ++ so atomics are needed. */ ++ return 2; ++} ++ ++int ++__get_nprocs (void) ++{ ++ /* Try /sys/devices/system/cpu/online first. */ ++ int result = get_nprocs_cpu_online (); ++ if (result != 0) ++ return result; ++ ++ /* Fall back to /proc/stat and sched_getaffinity. */ ++ return get_nprocs_fallback (); ++} ++libc_hidden_def (__get_nprocs) ++weak_alias (__get_nprocs, get_nprocs) ++ ++/* On some architectures it is possible to distinguish between configured ++ and active cpus. */ ++int ++__get_nprocs_conf (void) ++{ ++ /* Try /sys/devices/system/cpu/ first. */ ++ int result = get_nprocs_cpu (); ++ if (result != 0) ++ return result; ++ ++ /* Fall back to /proc/stat and sched_getaffinity. */ ++ return get_nprocs_fallback (); + } + libc_hidden_def (__get_nprocs_conf) + weak_alias (__get_nprocs_conf, get_nprocs_conf) +-- +2.27.0 + diff --git a/malloc-hugepage-0001-malloc-Add-madvise-support-for-Transparent-Huge-Page.patch b/malloc-hugepage-0001-malloc-Add-madvise-support-for-Transparent-Huge-Page.patch new file mode 100644 index 0000000000000000000000000000000000000000..1fc292a4ee3ab49f23cbb1dd86fb253123a732a0 --- /dev/null +++ b/malloc-hugepage-0001-malloc-Add-madvise-support-for-Transparent-Huge-Page.patch @@ -0,0 +1,532 @@ +From 5f6d8d97c69748180f0031dfa385aff75062c4d5 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Fri, 13 Aug 2021 08:36:29 -0300 +Subject: [PATCH 1/7] malloc: Add madvise support for Transparent Huge Pages + +Linux Transparent Huge Pages (THP) current supports three different +states: 'never', 'madvise', and 'always'. The 'never' is +self-explanatory and 'always' will enable THP for all anonymous +pages. However, 'madvise' is still the default for some system and +for such case THP will be only used if the memory range is explicity +advertise by the program through a madvise(MADV_HUGEPAGE) call. + +To enable it a new tunable is provided, 'glibc.malloc.hugetlb', +where setting to a value diffent than 0 enables the madvise call. + +This patch issues the madvise(MADV_HUGEPAGE) call after a successful +mmap() call at sysmalloc() with sizes larger than the default huge +page size. The madvise() call is disable is system does not support +THP or if it has the mode set to "never" and on Linux only support +one page size for THP, even if the architecture supports multiple +sizes. + +To test is a new rule is added tests-malloc-hugetlb1, which run the +addes tests with the required GLIBC_TUNABLE setting. + +Checked on x86_64-linux-gnu. + +Reviewed-by: DJ Delorie +--- + NEWS | 5 ++ + Rules | 19 ++++++ + elf/dl-tunables.list | 5 ++ + elf/tst-rtld-list-tunables.exp | 1 + + malloc/Makefile | 16 +++++ + malloc/arena.c | 5 ++ + malloc/malloc-internal.h | 1 + + malloc/malloc.c | 47 ++++++++++++++ + manual/tunables.texi | 10 +++ + sysdeps/generic/Makefile | 8 +++ + sysdeps/generic/malloc-hugepages.c | 31 +++++++++ + sysdeps/generic/malloc-hugepages.h | 37 +++++++++++ + sysdeps/unix/sysv/linux/malloc-hugepages.c | 74 ++++++++++++++++++++++ + 13 files changed, 259 insertions(+) + create mode 100644 sysdeps/generic/malloc-hugepages.c + create mode 100644 sysdeps/generic/malloc-hugepages.h + create mode 100644 sysdeps/unix/sysv/linux/malloc-hugepages.c + +diff --git a/NEWS b/NEWS +index 2532565d77..3b94dd209c 100644 +--- a/NEWS ++++ b/NEWS +@@ -92,6 +92,11 @@ Major new features: + variables. The GNU C Library manual has details on integration of + Restartable Sequences. + ++* On Linux, a new tunable, glibc.malloc.hugetlb, can be used to ++ make malloc issue madvise plus MADV_HUGEPAGE on mmap and sbrk calls. ++ Setting this might improve performance with Transparent Huge Pages madvise ++ mode depending of the workload. ++ + Deprecated and removed features, and other changes affecting compatibility: + + * The function pthread_mutex_consistent_np has been deprecated; programs +diff --git a/Rules b/Rules +index b1137afe71..5f5d9ba4cc 100644 +--- a/Rules ++++ b/Rules +@@ -157,6 +157,7 @@ tests: $(tests:%=$(objpfx)%.out) $(tests-internal:%=$(objpfx)%.out) \ + $(tests-container:%=$(objpfx)%.out) \ + $(tests-mcheck:%=$(objpfx)%-mcheck.out) \ + $(tests-malloc-check:%=$(objpfx)%-malloc-check.out) \ ++ $(tests-malloc-hugetlb1:%=$(objpfx)%-malloc-hugetlb1.out) \ + $(tests-special) $(tests-printers-out) + xtests: tests $(xtests:%=$(objpfx)%.out) $(xtests-special) + endif +@@ -168,6 +169,7 @@ tests-expected = + else + tests-expected = $(tests) $(tests-internal) $(tests-printers) \ + $(tests-container) $(tests-malloc-check:%=%-malloc-check) \ ++ $(tests-malloc-hugetlb1:%=%-malloc-hugetlb1) \ + $(tests-mcheck:%=%-mcheck) + endif + tests: +@@ -196,6 +198,7 @@ binaries-pie-notests = + endif + binaries-mcheck-tests = $(tests-mcheck:%=%-mcheck) + binaries-malloc-check-tests = $(tests-malloc-check:%=%-malloc-check) ++binaries-malloc-hugetlb1-tests = $(tests-malloc-hugetlb1:%=%-malloc-hugetlb1) + else + binaries-all-notests = + binaries-all-tests = $(tests) $(tests-internal) $(xtests) $(test-srcs) +@@ -207,6 +210,7 @@ binaries-pie-tests = + binaries-pie-notests = + binaries-mcheck-tests = + binaries-malloc-check-tests = ++binaries-malloc-hugetlb1-tests = + endif + + binaries-pie = $(binaries-pie-tests) $(binaries-pie-notests) +@@ -247,6 +251,14 @@ $(addprefix $(objpfx),$(binaries-malloc-check-tests)): %-malloc-check: %.o \ + $(+link-tests) + endif + ++ifneq "$(strip $(binaries-malloc-hugetlb1-tests))" "" ++$(addprefix $(objpfx),$(binaries-malloc-hugetlb1-tests)): %-malloc-hugetlb1: %.o \ ++ $(link-extra-libs-tests) \ ++ $(sort $(filter $(common-objpfx)lib%,$(link-libc))) \ ++ $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit) ++ $(+link-tests) ++endif ++ + ifneq "$(strip $(binaries-pie-tests))" "" + $(addprefix $(objpfx),$(binaries-pie-tests)): %: %.o \ + $(link-extra-libs-tests) \ +@@ -284,6 +296,13 @@ $(1)-malloc-check-ENV = MALLOC_CHECK_=3 \ + endef + $(foreach t,$(tests-malloc-check),$(eval $(call malloc-check-ENVS,$(t)))) + ++# All malloc-hugetlb1 tests will be run with GLIBC_TUNABLES=glibc.malloc.hugetlb=1 ++define malloc-hugetlb1-ENVS ++$(1)-malloc-hugetlb1-ENV += GLIBC_TUNABLES=glibc.malloc.hugetlb=1 ++endef ++$(foreach t,$(tests-malloc-hugetlb1),$(eval $(call malloc-hugetlb1-ENVS,$(t)))) ++ ++ + # mcheck tests need the debug DSO to support -lmcheck. + define mcheck-ENVS + $(1)-mcheck-ENV = LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so +diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list +index ffcd7f18d4..d1fd3f3e91 100644 +--- a/elf/dl-tunables.list ++++ b/elf/dl-tunables.list +@@ -92,6 +92,11 @@ glibc { + minval: 0 + security_level: SXID_IGNORE + } ++ hugetlb { ++ type: INT_32 ++ minval: 0 ++ maxval: 1 ++ } + } + cpu { + hwcap_mask { +diff --git a/elf/tst-rtld-list-tunables.exp b/elf/tst-rtld-list-tunables.exp +index 44e4834cfb..d8e363f2c5 100644 +--- a/elf/tst-rtld-list-tunables.exp ++++ b/elf/tst-rtld-list-tunables.exp +@@ -1,6 +1,7 @@ + glibc.malloc.arena_max: 0x0 (min: 0x1, max: 0x[f]+) + glibc.malloc.arena_test: 0x0 (min: 0x1, max: 0x[f]+) + glibc.malloc.check: 0 (min: 0, max: 3) ++glibc.malloc.hugetlb: 0 (min: 0, max: 1) + glibc.malloc.mmap_max: 0 (min: 0, max: 2147483647) + glibc.malloc.mmap_threshold: 0x0 (min: 0x0, max: 0x[f]+) + glibc.malloc.mxfast: 0x0 (min: 0x0, max: 0x[f]+) +diff --git a/malloc/Makefile b/malloc/Makefile +index 63cd7c0734..0137595e17 100644 +--- a/malloc/Makefile ++++ b/malloc/Makefile +@@ -78,6 +78,22 @@ tests-exclude-malloc-check = tst-malloc-check tst-malloc-usable \ + tests-malloc-check = $(filter-out $(tests-exclude-malloc-check) \ + $(tests-static),$(tests)) + ++# Run all testes with GLIBC_TUNABLES=glibc.malloc.hugetlb=1 that check the ++# Transparent Huge Pages support. We need exclude some tests that define ++# the ENV vars. ++tests-exclude-hugetlb1 = \ ++ tst-compathooks-off \ ++ tst-compathooks-on \ ++ tst-interpose-nothread \ ++ tst-interpose-thread \ ++ tst-interpose-static-nothread \ ++ tst-interpose-static-thread \ ++ tst-malloc-usable \ ++ tst-malloc-usable-tunables \ ++ tst-mallocstate ++tests-malloc-hugetlb1 = \ ++ $(filter-out $(tests-exclude-hugetlb1), $(tests)) ++ + # -lmcheck needs __malloc_initialize_hook, which was deprecated in 2.24. + ifeq ($(have-GLIBC_2.23)$(build-shared),yesyes) + # Tests that don't play well with mcheck. They are either bugs in mcheck or +diff --git a/malloc/arena.c b/malloc/arena.c +index 78ef4cf18c..cd00c7bef4 100644 +--- a/malloc/arena.c ++++ b/malloc/arena.c +@@ -230,6 +230,7 @@ TUNABLE_CALLBACK_FNDECL (set_tcache_count, size_t) + TUNABLE_CALLBACK_FNDECL (set_tcache_unsorted_limit, size_t) + #endif + TUNABLE_CALLBACK_FNDECL (set_mxfast, size_t) ++TUNABLE_CALLBACK_FNDECL (set_hugetlb, int32_t) + #else + /* Initialization routine. */ + #include +@@ -330,6 +331,7 @@ ptmalloc_init (void) + TUNABLE_CALLBACK (set_tcache_unsorted_limit)); + # endif + TUNABLE_GET (mxfast, size_t, TUNABLE_CALLBACK (set_mxfast)); ++ TUNABLE_GET (hugetlb, int32_t, TUNABLE_CALLBACK (set_hugetlb)); + #else + if (__glibc_likely (_environ != NULL)) + { +@@ -508,6 +510,9 @@ new_heap (size_t size, size_t top_pad) + __munmap (p2, HEAP_MAX_SIZE); + return 0; + } ++ ++ madvise_thp (p2, size); ++ + h = (heap_info *) p2; + h->size = size; + h->mprotect_size = size; +diff --git a/malloc/malloc-internal.h b/malloc/malloc-internal.h +index 0c7b5a183c..7493e34d86 100644 +--- a/malloc/malloc-internal.h ++++ b/malloc/malloc-internal.h +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + /* Called in the parent process before a fork. */ + void __malloc_fork_lock_parent (void) attribute_hidden; +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 095d97a3be..c75841b841 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -1880,6 +1880,11 @@ struct malloc_par + INTERNAL_SIZE_T arena_test; + INTERNAL_SIZE_T arena_max; + ++#if HAVE_TUNABLES ++ /* Transparent Large Page support. */ ++ INTERNAL_SIZE_T thp_pagesize; ++#endif ++ + /* Memory map support */ + int n_mmaps; + int n_mmaps_max; +@@ -2008,6 +2013,20 @@ free_perturb (char *p, size_t n) + + #include + ++/* ----------- Routines dealing with transparent huge pages ----------- */ ++ ++static inline void ++madvise_thp (void *p, INTERNAL_SIZE_T size) ++{ ++#if HAVE_TUNABLES && defined (MADV_HUGEPAGE) ++ /* Do not consider areas smaller than a huge page or if the tunable is ++ not active. */ ++ if (mp_.thp_pagesize == 0 || size < mp_.thp_pagesize) ++ return; ++ __madvise (p, size, MADV_HUGEPAGE); ++#endif ++} ++ + /* ------------------- Support for multiple arenas -------------------- */ + #include "arena.c" + +@@ -2445,6 +2464,8 @@ sysmalloc (INTERNAL_SIZE_T nb, mstate av) + + if (mm != MAP_FAILED) + { ++ madvise_thp (mm, size); ++ + /* + The offset to the start of the mmapped region is stored + in the prev_size field of the chunk. This allows us to adjust +@@ -2606,6 +2627,8 @@ sysmalloc (INTERNAL_SIZE_T nb, mstate av) + if (size > 0) + { + brk = (char *) (MORECORE (size)); ++ if (brk != (char *) (MORECORE_FAILURE)) ++ madvise_thp (brk, size); + LIBC_PROBE (memory_sbrk_more, 2, brk, size); + } + +@@ -2637,6 +2660,8 @@ sysmalloc (INTERNAL_SIZE_T nb, mstate av) + + if (mbrk != MAP_FAILED) + { ++ madvise_thp (mbrk, size); ++ + /* We do not need, and cannot use, another sbrk call to find end */ + brk = mbrk; + snd_brk = brk + size; +@@ -2748,6 +2773,8 @@ sysmalloc (INTERNAL_SIZE_T nb, mstate av) + correction = 0; + snd_brk = (char *) (MORECORE (0)); + } ++ else ++ madvise_thp (snd_brk, correction); + } + + /* handle non-contiguous cases */ +@@ -2988,6 +3015,8 @@ mremap_chunk (mchunkptr p, size_t new_size) + if (cp == MAP_FAILED) + return 0; + ++ madvise_thp (cp, new_size); ++ + p = (mchunkptr) (cp + offset); + + assert (aligned_OK (chunk2mem (p))); +@@ -5316,6 +5345,24 @@ do_set_mxfast (size_t value) + return 0; + } + ++#if HAVE_TUNABLES ++static __always_inline int ++do_set_hugetlb (int32_t value) ++{ ++ if (value == 1) ++ { ++ enum malloc_thp_mode_t thp_mode = __malloc_thp_mode (); ++ /* ++ Only enable THP madvise usage if system does support it and ++ has 'madvise' mode. Otherwise the madvise() call is wasteful. ++ */ ++ if (thp_mode == malloc_thp_mode_madvise) ++ mp_.thp_pagesize = __malloc_default_thp_pagesize (); ++ } ++ return 0; ++} ++#endif ++ + int + __libc_mallopt (int param_number, int value) + { +diff --git a/manual/tunables.texi b/manual/tunables.texi +index 28ff502990..9ca6e3f603 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -270,6 +270,16 @@ pointer, so add 4 on 32-bit systems or 8 on 64-bit systems to the size + passed to @code{malloc} for the largest bin size to enable. + @end deftp + ++@deftp Tunable glibc.malloc.hugetlb ++This tunable controls the usage of Huge Pages on @code{malloc} calls. The ++default value is @code{0}, which disables any additional support on ++@code{malloc}. ++ ++Setting its value to @code{1} enables the use of @code{madvise} with ++@code{MADV_HUGEPAGE} after memory allocation with @code{mmap}. It is enabled ++only if the system supports Transparent Huge Page (currently only on Linux). ++@end deftp ++ + @node Dynamic Linking Tunables + @section Dynamic Linking Tunables + @cindex dynamic linking tunables +diff --git a/sysdeps/generic/Makefile b/sysdeps/generic/Makefile +index a209e85cc4..8eef83c94d 100644 +--- a/sysdeps/generic/Makefile ++++ b/sysdeps/generic/Makefile +@@ -27,3 +27,11 @@ sysdep_routines += framestate unwind-pe + shared-only-routines += framestate unwind-pe + endif + endif ++ ++ifeq ($(subdir),malloc) ++sysdep_malloc_debug_routines += malloc-hugepages ++endif ++ ++ifeq ($(subdir),misc) ++sysdep_routines += malloc-hugepages ++endif +diff --git a/sysdeps/generic/malloc-hugepages.c b/sysdeps/generic/malloc-hugepages.c +new file mode 100644 +index 0000000000..8fb459a263 +--- /dev/null ++++ b/sysdeps/generic/malloc-hugepages.c +@@ -0,0 +1,31 @@ ++/* Huge Page support. Generic implementation. ++ 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; see the file COPYING.LIB. If ++ not, see . */ ++ ++#include ++ ++unsigned long int ++__malloc_default_thp_pagesize (void) ++{ ++ return 0; ++} ++ ++enum malloc_thp_mode_t ++__malloc_thp_mode (void) ++{ ++ return malloc_thp_mode_not_supported; ++} +diff --git a/sysdeps/generic/malloc-hugepages.h b/sysdeps/generic/malloc-hugepages.h +new file mode 100644 +index 0000000000..f5a442e328 +--- /dev/null ++++ b/sysdeps/generic/malloc-hugepages.h +@@ -0,0 +1,37 @@ ++/* Malloc huge page support. Generic implementation. ++ 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; see the file COPYING.LIB. If ++ not, see . */ ++ ++#ifndef _MALLOC_HUGEPAGES_H ++#define _MALLOC_HUGEPAGES_H ++ ++#include ++ ++/* Return the default transparent huge page size. */ ++unsigned long int __malloc_default_thp_pagesize (void) attribute_hidden; ++ ++enum malloc_thp_mode_t ++{ ++ malloc_thp_mode_always, ++ malloc_thp_mode_madvise, ++ malloc_thp_mode_never, ++ malloc_thp_mode_not_supported ++}; ++ ++enum malloc_thp_mode_t __malloc_thp_mode (void) attribute_hidden; ++ ++#endif /* _MALLOC_HUGEPAGES_H */ +diff --git a/sysdeps/unix/sysv/linux/malloc-hugepages.c b/sysdeps/unix/sysv/linux/malloc-hugepages.c +new file mode 100644 +index 0000000000..7497e07260 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/malloc-hugepages.c +@@ -0,0 +1,74 @@ ++/* Huge Page support. Linux implementation. ++ 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; see the file COPYING.LIB. If ++ not, see . */ ++ ++#include ++#include ++#include ++ ++unsigned long int ++__malloc_default_thp_pagesize (void) ++{ ++ int fd = __open64_nocancel ( ++ "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size", O_RDONLY); ++ if (fd == -1) ++ return 0; ++ ++ char str[INT_BUFSIZE_BOUND (unsigned long int)]; ++ ssize_t s = __read_nocancel (fd, str, sizeof (str)); ++ __close_nocancel (fd); ++ if (s < 0) ++ return 0; ++ ++ unsigned long int r = 0; ++ for (ssize_t i = 0; i < s; i++) ++ { ++ if (str[i] == '\n') ++ break; ++ r *= 10; ++ r += str[i] - '0'; ++ } ++ return r; ++} ++ ++enum malloc_thp_mode_t ++__malloc_thp_mode (void) ++{ ++ int fd = __open64_nocancel ("/sys/kernel/mm/transparent_hugepage/enabled", ++ O_RDONLY); ++ if (fd == -1) ++ return malloc_thp_mode_not_supported; ++ ++ static const char mode_always[] = "[always] madvise never\n"; ++ static const char mode_madvise[] = "always [madvise] never\n"; ++ static const char mode_never[] = "always madvise [never]\n"; ++ ++ char str[sizeof(mode_always)]; ++ ssize_t s = __read_nocancel (fd, str, sizeof (str)); ++ __close_nocancel (fd); ++ ++ if (s == sizeof (mode_always) - 1) ++ { ++ if (strcmp (str, mode_always) == 0) ++ return malloc_thp_mode_always; ++ else if (strcmp (str, mode_madvise) == 0) ++ return malloc_thp_mode_madvise; ++ else if (strcmp (str, mode_never) == 0) ++ return malloc_thp_mode_never; ++ } ++ return malloc_thp_mode_not_supported; ++} +-- +2.33.0 + diff --git a/malloc-hugepage-0002-malloc-Add-THP-madvise-support-for-sbrk.patch b/malloc-hugepage-0002-malloc-Add-THP-madvise-support-for-sbrk.patch new file mode 100644 index 0000000000000000000000000000000000000000..58f2abfd05cebe9a202e5025f449a0f57c0763f1 --- /dev/null +++ b/malloc-hugepage-0002-malloc-Add-THP-madvise-support-for-sbrk.patch @@ -0,0 +1,111 @@ +From 7478c9959ae409f7b3d63146943575d6ee745352 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Fri, 13 Aug 2021 10:06:04 -0300 +Subject: [PATCH 2/7] malloc: Add THP/madvise support for sbrk + +To increase effectiveness with Transparent Huge Page with madvise, the +large page size is use instead page size for sbrk increment for the +main arena. + +Checked on x86_64-linux-gnu. + +Reviewed-by: DJ Delorie +--- + include/libc-pointer-arith.h | 8 ++++++++ + malloc/malloc.c | 34 +++++++++++++++++++++++++++++----- + 2 files changed, 37 insertions(+), 5 deletions(-) + +diff --git a/include/libc-pointer-arith.h b/include/libc-pointer-arith.h +index 04ba537617..55dccc10ac 100644 +--- a/include/libc-pointer-arith.h ++++ b/include/libc-pointer-arith.h +@@ -60,4 +60,12 @@ + #define PTR_ALIGN_UP(base, size) \ + ((__typeof__ (base)) ALIGN_UP ((uintptr_t) (base), (size))) + ++/* Check if BASE is aligned on SIZE */ ++#define PTR_IS_ALIGNED(base, size) \ ++ ((((uintptr_t) (base)) & (size - 1)) == 0) ++ ++/* Returns the ptrdiff_t diference between P1 and P2. */ ++#define PTR_DIFF(p1, p2) \ ++ ((ptrdiff_t)((uintptr_t)(p1) - (uintptr_t)(p2))) ++ + #endif +diff --git a/malloc/malloc.c b/malloc/malloc.c +index c75841b841..57db4dd9a5 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -2023,6 +2023,16 @@ madvise_thp (void *p, INTERNAL_SIZE_T size) + not active. */ + if (mp_.thp_pagesize == 0 || size < mp_.thp_pagesize) + return; ++ ++ /* Linux requires the input address to be page-aligned, and unaligned ++ inputs happens only for initial data segment. */ ++ if (__glibc_unlikely (!PTR_IS_ALIGNED (p, GLRO (dl_pagesize)))) ++ { ++ void *q = PTR_ALIGN_DOWN (p, GLRO (dl_pagesize)); ++ size += PTR_DIFF (p, q); ++ p = q; ++ } ++ + __madvise (p, size, MADV_HUGEPAGE); + #endif + } +@@ -2609,14 +2619,25 @@ sysmalloc (INTERNAL_SIZE_T nb, mstate av) + size -= old_size; + + /* +- Round to a multiple of page size. ++ Round to a multiple of page size or huge page size. + If MORECORE is not contiguous, this ensures that we only call it + with whole-page arguments. And if MORECORE is contiguous and + this is not first time through, this preserves page-alignment of + previous calls. Otherwise, we correct to page-align below. + */ + +- size = ALIGN_UP (size, pagesize); ++#if HAVE_TUNABLES && defined (MADV_HUGEPAGE) ++ /* Defined in brk.c. */ ++ extern void *__curbrk; ++ if (__glibc_unlikely (mp_.thp_pagesize != 0)) ++ { ++ uintptr_t top = ALIGN_UP ((uintptr_t) __curbrk + size, ++ mp_.thp_pagesize); ++ size = top - (uintptr_t) __curbrk; ++ } ++ else ++#endif ++ size = ALIGN_UP (size, GLRO(dl_pagesize)); + + /* + Don't try to call MORECORE if argument is so big as to appear +@@ -2899,10 +2920,8 @@ systrim (size_t pad, mstate av) + long released; /* Amount actually released */ + char *current_brk; /* address returned by pre-check sbrk call */ + char *new_brk; /* address returned by post-check sbrk call */ +- size_t pagesize; + long top_area; + +- pagesize = GLRO (dl_pagesize); + top_size = chunksize (av->top); + + top_area = top_size - MINSIZE - 1; +@@ -2910,7 +2929,12 @@ systrim (size_t pad, mstate av) + return 0; + + /* Release in pagesize units and round down to the nearest page. */ +- extra = ALIGN_DOWN(top_area - pad, pagesize); ++#if HAVE_TUNABLES && defined (MADV_HUGEPAGE) ++ if (__glibc_unlikely (mp_.thp_pagesize != 0)) ++ extra = ALIGN_DOWN (top_area - pad, mp_.thp_pagesize); ++ else ++#endif ++ extra = ALIGN_DOWN (top_area - pad, GLRO(dl_pagesize)); + + if (extra == 0) + return 0; +-- +2.33.0 + diff --git a/malloc-hugepage-0003-malloc-Move-mmap-logic-to-its-own-function.patch b/malloc-hugepage-0003-malloc-Move-mmap-logic-to-its-own-function.patch new file mode 100644 index 0000000000000000000000000000000000000000..5b1768bff898c3ff6d04ce9f0e5cdf1bbebe0d43 --- /dev/null +++ b/malloc-hugepage-0003-malloc-Move-mmap-logic-to-its-own-function.patch @@ -0,0 +1,205 @@ +From 6cc3ccc67e0dda654fc839377af2818a296f0007 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Mon, 16 Aug 2021 11:14:20 -0300 +Subject: [PATCH 3/7] malloc: Move mmap logic to its own function + +So it can be used with different pagesize and flags. + +Reviewed-by: DJ Delorie +--- + malloc/malloc.c | 164 ++++++++++++++++++++++++++---------------------- + 1 file changed, 88 insertions(+), 76 deletions(-) + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 57db4dd9a5..6b6ec53db1 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -2412,6 +2412,85 @@ do_check_malloc_state (mstate av) + be extended or replaced. + */ + ++static void * ++sysmalloc_mmap (INTERNAL_SIZE_T nb, size_t pagesize, int extra_flags, mstate av) ++{ ++ long int size; ++ ++ /* ++ Round up size to nearest page. For mmapped chunks, the overhead is one ++ SIZE_SZ unit larger than for normal chunks, because there is no ++ following chunk whose prev_size field could be used. ++ ++ See the front_misalign handling below, for glibc there is no need for ++ further alignments unless we have have high alignment. ++ */ ++ if (MALLOC_ALIGNMENT == CHUNK_HDR_SZ) ++ size = ALIGN_UP (nb + SIZE_SZ, pagesize); ++ else ++ size = ALIGN_UP (nb + SIZE_SZ + MALLOC_ALIGN_MASK, pagesize); ++ ++ /* Don't try if size wraps around 0. */ ++ if ((unsigned long) (size) <= (unsigned long) (nb)) ++ return MAP_FAILED; ++ ++ char *mm = (char *) MMAP (0, size, ++ mtag_mmap_flags | PROT_READ | PROT_WRITE, ++ extra_flags); ++ if (mm == MAP_FAILED) ++ return mm; ++ ++ madvise_thp (mm, size); ++ ++ /* ++ The offset to the start of the mmapped region is stored in the prev_size ++ field of the chunk. This allows us to adjust returned start address to ++ meet alignment requirements here and in memalign(), and still be able to ++ compute proper address argument for later munmap in free() and realloc(). ++ */ ++ ++ INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of new space */ ++ ++ if (MALLOC_ALIGNMENT == CHUNK_HDR_SZ) ++ { ++ /* For glibc, chunk2mem increases the address by CHUNK_HDR_SZ and ++ MALLOC_ALIGN_MASK is CHUNK_HDR_SZ-1. Each mmap'ed area is page ++ aligned and therefore definitely MALLOC_ALIGN_MASK-aligned. */ ++ assert (((INTERNAL_SIZE_T) chunk2mem (mm) & MALLOC_ALIGN_MASK) == 0); ++ front_misalign = 0; ++ } ++ else ++ front_misalign = (INTERNAL_SIZE_T) chunk2mem (mm) & MALLOC_ALIGN_MASK; ++ ++ mchunkptr p; /* the allocated/returned chunk */ ++ ++ if (front_misalign > 0) ++ { ++ ptrdiff_t correction = MALLOC_ALIGNMENT - front_misalign; ++ p = (mchunkptr) (mm + correction); ++ set_prev_size (p, correction); ++ set_head (p, (size - correction) | IS_MMAPPED); ++ } ++ else ++ { ++ p = (mchunkptr) mm; ++ set_prev_size (p, 0); ++ set_head (p, size | IS_MMAPPED); ++ } ++ ++ /* update statistics */ ++ int new = atomic_exchange_and_add (&mp_.n_mmaps, 1) + 1; ++ atomic_max (&mp_.max_n_mmaps, new); ++ ++ unsigned long sum; ++ sum = atomic_exchange_and_add (&mp_.mmapped_mem, size) + size; ++ atomic_max (&mp_.max_mmapped_mem, sum); ++ ++ check_chunk (av, p); ++ ++ return chunk2mem (p); ++} ++ + static void * + sysmalloc (INTERNAL_SIZE_T nb, mstate av) + { +@@ -2449,81 +2528,10 @@ sysmalloc (INTERNAL_SIZE_T nb, mstate av) + || ((unsigned long) (nb) >= (unsigned long) (mp_.mmap_threshold) + && (mp_.n_mmaps < mp_.n_mmaps_max))) + { +- char *mm; /* return value from mmap call*/ +- +- try_mmap: +- /* +- Round up size to nearest page. For mmapped chunks, the overhead +- is one SIZE_SZ unit larger than for normal chunks, because there +- is no following chunk whose prev_size field could be used. +- +- See the front_misalign handling below, for glibc there is no +- need for further alignments unless we have have high alignment. +- */ +- if (MALLOC_ALIGNMENT == CHUNK_HDR_SZ) +- size = ALIGN_UP (nb + SIZE_SZ, pagesize); +- else +- size = ALIGN_UP (nb + SIZE_SZ + MALLOC_ALIGN_MASK, pagesize); ++ char *mm = sysmalloc_mmap (nb, pagesize, 0, av); ++ if (mm != MAP_FAILED) ++ return mm; + tried_mmap = true; +- +- /* Don't try if size wraps around 0 */ +- if ((unsigned long) (size) > (unsigned long) (nb)) +- { +- mm = (char *) (MMAP (0, size, +- mtag_mmap_flags | PROT_READ | PROT_WRITE, 0)); +- +- if (mm != MAP_FAILED) +- { +- madvise_thp (mm, size); +- +- /* +- The offset to the start of the mmapped region is stored +- in the prev_size field of the chunk. This allows us to adjust +- returned start address to meet alignment requirements here +- and in memalign(), and still be able to compute proper +- address argument for later munmap in free() and realloc(). +- */ +- +- if (MALLOC_ALIGNMENT == CHUNK_HDR_SZ) +- { +- /* For glibc, chunk2mem increases the address by +- CHUNK_HDR_SZ and MALLOC_ALIGN_MASK is +- CHUNK_HDR_SZ-1. Each mmap'ed area is page +- aligned and therefore definitely +- MALLOC_ALIGN_MASK-aligned. */ +- assert (((INTERNAL_SIZE_T) chunk2mem (mm) & MALLOC_ALIGN_MASK) == 0); +- front_misalign = 0; +- } +- else +- front_misalign = (INTERNAL_SIZE_T) chunk2mem (mm) & MALLOC_ALIGN_MASK; +- if (front_misalign > 0) +- { +- correction = MALLOC_ALIGNMENT - front_misalign; +- p = (mchunkptr) (mm + correction); +- set_prev_size (p, correction); +- set_head (p, (size - correction) | IS_MMAPPED); +- } +- else +- { +- p = (mchunkptr) mm; +- set_prev_size (p, 0); +- set_head (p, size | IS_MMAPPED); +- } +- +- /* update statistics */ +- +- int new = atomic_exchange_and_add (&mp_.n_mmaps, 1) + 1; +- atomic_max (&mp_.max_n_mmaps, new); +- +- unsigned long sum; +- sum = atomic_exchange_and_add (&mp_.mmapped_mem, size) + size; +- atomic_max (&mp_.max_mmapped_mem, sum); +- +- check_chunk (av, p); +- +- return chunk2mem (p); +- } +- } + } + + /* There are no usable arenas and mmap also failed. */ +@@ -2600,8 +2608,12 @@ sysmalloc (INTERNAL_SIZE_T nb, mstate av) + } + } + else if (!tried_mmap) +- /* We can at least try to use to mmap memory. */ +- goto try_mmap; ++ { ++ /* We can at least try to use to mmap memory. */ ++ char *mm = sysmalloc_mmap (nb, pagesize, 0, av); ++ if (mm != MAP_FAILED) ++ return mm; ++ } + } + else /* av == main_arena */ + +-- +2.33.0 + diff --git a/malloc-hugepage-0004-malloc-Add-Huge-Page-support-for-mmap.patch b/malloc-hugepage-0004-malloc-Add-Huge-Page-support-for-mmap.patch new file mode 100644 index 0000000000000000000000000000000000000000..1969a1fe84a3a2e3c21137958b7e3238da9e5255 --- /dev/null +++ b/malloc-hugepage-0004-malloc-Add-Huge-Page-support-for-mmap.patch @@ -0,0 +1,476 @@ +From 98d5fcb8d099a1a868e032c89891c395a2f365c5 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Mon, 16 Aug 2021 15:08:27 -0300 +Subject: [PATCH 4/7] malloc: Add Huge Page support for mmap + +With the morecore hook removed, there is not easy way to provide huge +pages support on with glibc allocator without resorting to transparent +huge pages. And some users and programs do prefer to use the huge pages +directly instead of THP for multiple reasons: no splitting, re-merging +by the VM, no TLB shootdowns for running processes, fast allocation +from the reserve pool, no competition with the rest of the processes +unlike THP, no swapping all, etc. + +This patch extends the 'glibc.malloc.hugetlb' tunable: the value +'2' means to use huge pages directly with the system default size, +while a positive value means and specific page size that is matched +against the supported ones by the system. + +Currently only memory allocated on sysmalloc() is handled, the arenas +still uses the default system page size. + +To test is a new rule is added tests-malloc-hugetlb2, which run the +addes tests with the required GLIBC_TUNABLE setting. On systems without +a reserved huge pages pool, is just stress the mmap(MAP_HUGETLB) +allocation failure. To improve test coverage it is required to create +a pool with some allocated pages. + +Checked on x86_64-linux-gnu. + +Reviewed-by: DJ Delorie +--- + NEWS | 8 +- + Rules | 17 +++ + elf/dl-tunables.list | 3 +- + elf/tst-rtld-list-tunables.exp | 2 +- + malloc/Makefile | 8 +- + malloc/arena.c | 4 +- + malloc/malloc.c | 31 ++++- + manual/tunables.texi | 7 ++ + sysdeps/generic/malloc-hugepages.c | 8 ++ + sysdeps/generic/malloc-hugepages.h | 7 ++ + sysdeps/unix/sysv/linux/malloc-hugepages.c | 127 +++++++++++++++++++++ + 11 files changed, 207 insertions(+), 15 deletions(-) + +diff --git a/NEWS b/NEWS +index 3b94dd209c..c7200cd4e8 100644 +--- a/NEWS ++++ b/NEWS +@@ -93,9 +93,11 @@ Major new features: + Restartable Sequences. + + * On Linux, a new tunable, glibc.malloc.hugetlb, can be used to +- make malloc issue madvise plus MADV_HUGEPAGE on mmap and sbrk calls. +- Setting this might improve performance with Transparent Huge Pages madvise +- mode depending of the workload. ++ either make malloc issue madvise plus MADV_HUGEPAGE on mmap and sbrk ++ or to use huge pages directly with mmap calls with the MAP_HUGETLB ++ flags). The former can improve performance when Transparent Huge Pages ++ is set to 'madvise' mode while the latter uses the system reserved ++ huge pages. + + Deprecated and removed features, and other changes affecting compatibility: + +diff --git a/Rules b/Rules +index 5f5d9ba4cc..be34982daa 100644 +--- a/Rules ++++ b/Rules +@@ -158,6 +158,7 @@ tests: $(tests:%=$(objpfx)%.out) $(tests-internal:%=$(objpfx)%.out) \ + $(tests-mcheck:%=$(objpfx)%-mcheck.out) \ + $(tests-malloc-check:%=$(objpfx)%-malloc-check.out) \ + $(tests-malloc-hugetlb1:%=$(objpfx)%-malloc-hugetlb1.out) \ ++ $(tests-malloc-hugetlb2:%=$(objpfx)%-malloc-hugetlb2.out) \ + $(tests-special) $(tests-printers-out) + xtests: tests $(xtests:%=$(objpfx)%.out) $(xtests-special) + endif +@@ -170,6 +171,7 @@ else + tests-expected = $(tests) $(tests-internal) $(tests-printers) \ + $(tests-container) $(tests-malloc-check:%=%-malloc-check) \ + $(tests-malloc-hugetlb1:%=%-malloc-hugetlb1) \ ++ $(tests-malloc-hugetlb2:%=%-malloc-hugetlb2) \ + $(tests-mcheck:%=%-mcheck) + endif + tests: +@@ -199,6 +201,7 @@ endif + binaries-mcheck-tests = $(tests-mcheck:%=%-mcheck) + binaries-malloc-check-tests = $(tests-malloc-check:%=%-malloc-check) + binaries-malloc-hugetlb1-tests = $(tests-malloc-hugetlb1:%=%-malloc-hugetlb1) ++binaries-malloc-hugetlb2-tests = $(tests-malloc-hugetlb2:%=%-malloc-hugetlb2) + else + binaries-all-notests = + binaries-all-tests = $(tests) $(tests-internal) $(xtests) $(test-srcs) +@@ -211,6 +214,7 @@ binaries-pie-notests = + binaries-mcheck-tests = + binaries-malloc-check-tests = + binaries-malloc-hugetlb1-tests = ++binaries-malloc-hugetlb2-tests = + endif + + binaries-pie = $(binaries-pie-tests) $(binaries-pie-notests) +@@ -259,6 +263,14 @@ $(addprefix $(objpfx),$(binaries-malloc-hugetlb1-tests)): %-malloc-hugetlb1: %.o + $(+link-tests) + endif + ++ifneq "$(strip $(binaries-malloc-hugetlb2-tests))" "" ++$(addprefix $(objpfx),$(binaries-malloc-hugetlb2-tests)): %-malloc-hugetlb2: %.o \ ++ $(link-extra-libs-tests) \ ++ $(sort $(filter $(common-objpfx)lib%,$(link-libc))) \ ++ $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit) ++ $(+link-tests) ++endif ++ + ifneq "$(strip $(binaries-pie-tests))" "" + $(addprefix $(objpfx),$(binaries-pie-tests)): %: %.o \ + $(link-extra-libs-tests) \ +@@ -302,6 +314,11 @@ $(1)-malloc-hugetlb1-ENV += GLIBC_TUNABLES=glibc.malloc.hugetlb=1 + endef + $(foreach t,$(tests-malloc-hugetlb1),$(eval $(call malloc-hugetlb1-ENVS,$(t)))) + ++# All malloc-hugetlb2 tests will be run with GLIBC_TUNABLE=glibc.malloc.hugetlb=2 ++define malloc-hugetlb2-ENVS ++$(1)-malloc-hugetlb2-ENV += GLIBC_TUNABLES=glibc.malloc.hugetlb=2 ++endef ++$(foreach t,$(tests-malloc-hugetlb2),$(eval $(call malloc-hugetlb2-ENVS,$(t)))) + + # mcheck tests need the debug DSO to support -lmcheck. + define mcheck-ENVS +diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list +index d1fd3f3e91..845d521a43 100644 +--- a/elf/dl-tunables.list ++++ b/elf/dl-tunables.list +@@ -93,9 +93,8 @@ glibc { + security_level: SXID_IGNORE + } + hugetlb { +- type: INT_32 ++ type: SIZE_T + minval: 0 +- maxval: 1 + } + } + cpu { +diff --git a/elf/tst-rtld-list-tunables.exp b/elf/tst-rtld-list-tunables.exp +index d8e363f2c5..cdfdb56a94 100644 +--- a/elf/tst-rtld-list-tunables.exp ++++ b/elf/tst-rtld-list-tunables.exp +@@ -1,7 +1,7 @@ + glibc.malloc.arena_max: 0x0 (min: 0x1, max: 0x[f]+) + glibc.malloc.arena_test: 0x0 (min: 0x1, max: 0x[f]+) + glibc.malloc.check: 0 (min: 0, max: 3) +-glibc.malloc.hugetlb: 0 (min: 0, max: 1) ++glibc.malloc.hugetlb: 0x0 (min: 0x0, max: 0x[f]+) + glibc.malloc.mmap_max: 0 (min: 0, max: 2147483647) + glibc.malloc.mmap_threshold: 0x0 (min: 0x0, max: 0x[f]+) + glibc.malloc.mxfast: 0x0 (min: 0x0, max: 0x[f]+) +diff --git a/malloc/Makefile b/malloc/Makefile +index 0137595e17..e9a6666d22 100644 +--- a/malloc/Makefile ++++ b/malloc/Makefile +@@ -78,9 +78,9 @@ tests-exclude-malloc-check = tst-malloc-check tst-malloc-usable \ + tests-malloc-check = $(filter-out $(tests-exclude-malloc-check) \ + $(tests-static),$(tests)) + +-# Run all testes with GLIBC_TUNABLES=glibc.malloc.hugetlb=1 that check the +-# Transparent Huge Pages support. We need exclude some tests that define +-# the ENV vars. ++# Run all tests with GLIBC_TUNABLES=glibc.malloc.hugetlb={1,2} which check ++# the Transparent Huge Pages support (1) or automatic huge page support (2). ++# We need exclude some tests that define the ENV vars. + tests-exclude-hugetlb1 = \ + tst-compathooks-off \ + tst-compathooks-on \ +@@ -93,6 +93,8 @@ tests-exclude-hugetlb1 = \ + tst-mallocstate + tests-malloc-hugetlb1 = \ + $(filter-out $(tests-exclude-hugetlb1), $(tests)) ++tests-malloc-hugetlb2 = \ ++ $(filter-out $(tests-exclude-hugetlb1), $(tests)) + + # -lmcheck needs __malloc_initialize_hook, which was deprecated in 2.24. + ifeq ($(have-GLIBC_2.23)$(build-shared),yesyes) +diff --git a/malloc/arena.c b/malloc/arena.c +index cd00c7bef4..9a6e1af2bd 100644 +--- a/malloc/arena.c ++++ b/malloc/arena.c +@@ -230,7 +230,7 @@ TUNABLE_CALLBACK_FNDECL (set_tcache_count, size_t) + TUNABLE_CALLBACK_FNDECL (set_tcache_unsorted_limit, size_t) + #endif + TUNABLE_CALLBACK_FNDECL (set_mxfast, size_t) +-TUNABLE_CALLBACK_FNDECL (set_hugetlb, int32_t) ++TUNABLE_CALLBACK_FNDECL (set_hugetlb, size_t) + #else + /* Initialization routine. */ + #include +@@ -331,7 +331,7 @@ ptmalloc_init (void) + TUNABLE_CALLBACK (set_tcache_unsorted_limit)); + # endif + TUNABLE_GET (mxfast, size_t, TUNABLE_CALLBACK (set_mxfast)); +- TUNABLE_GET (hugetlb, int32_t, TUNABLE_CALLBACK (set_hugetlb)); ++ TUNABLE_GET (hugetlb, size_t, TUNABLE_CALLBACK (set_hugetlb)); + #else + if (__glibc_likely (_environ != NULL)) + { +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 6b6ec53db1..75efdc2ee7 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -1883,6 +1883,10 @@ struct malloc_par + #if HAVE_TUNABLES + /* Transparent Large Page support. */ + INTERNAL_SIZE_T thp_pagesize; ++ /* A value different than 0 means to align mmap allocation to hp_pagesize ++ add hp_flags on flags. */ ++ INTERNAL_SIZE_T hp_pagesize; ++ int hp_flags; + #endif + + /* Memory map support */ +@@ -2440,7 +2444,10 @@ sysmalloc_mmap (INTERNAL_SIZE_T nb, size_t pagesize, int extra_flags, mstate av) + if (mm == MAP_FAILED) + return mm; + +- madvise_thp (mm, size); ++#ifdef MAP_HUGETLB ++ if (!(extra_flags & MAP_HUGETLB)) ++ madvise_thp (mm, size); ++#endif + + /* + The offset to the start of the mmapped region is stored in the prev_size +@@ -2528,7 +2535,18 @@ sysmalloc (INTERNAL_SIZE_T nb, mstate av) + || ((unsigned long) (nb) >= (unsigned long) (mp_.mmap_threshold) + && (mp_.n_mmaps < mp_.n_mmaps_max))) + { +- char *mm = sysmalloc_mmap (nb, pagesize, 0, av); ++ char *mm; ++#if HAVE_TUNABLES ++ if (mp_.hp_pagesize > 0 && nb >= mp_.hp_pagesize) ++ { ++ /* There is no need to isse the THP madvise call if Huge Pages are ++ used directly. */ ++ mm = sysmalloc_mmap (nb, mp_.hp_pagesize, mp_.hp_flags, av); ++ if (mm != MAP_FAILED) ++ return mm; ++ } ++#endif ++ mm = sysmalloc_mmap (nb, pagesize, 0, av); + if (mm != MAP_FAILED) + return mm; + tried_mmap = true; +@@ -2609,7 +2627,9 @@ sysmalloc (INTERNAL_SIZE_T nb, mstate av) + } + else if (!tried_mmap) + { +- /* We can at least try to use to mmap memory. */ ++ /* We can at least try to use to mmap memory. If new_heap fails ++ it is unlikely that trying to allocate huge pages will ++ succeed. */ + char *mm = sysmalloc_mmap (nb, pagesize, 0, av); + if (mm != MAP_FAILED) + return mm; +@@ -5383,7 +5403,7 @@ do_set_mxfast (size_t value) + + #if HAVE_TUNABLES + static __always_inline int +-do_set_hugetlb (int32_t value) ++do_set_hugetlb (size_t value) + { + if (value == 1) + { +@@ -5395,6 +5415,9 @@ do_set_hugetlb (int32_t value) + if (thp_mode == malloc_thp_mode_madvise) + mp_.thp_pagesize = __malloc_default_thp_pagesize (); + } ++ else if (value >= 2) ++ __malloc_hugepage_config (value == 2 ? 0 : value, &mp_.hp_pagesize, ++ &mp_.hp_flags); + return 0; + } + #endif +diff --git a/manual/tunables.texi b/manual/tunables.texi +index 9ca6e3f603..58a47b2e9b 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -278,6 +278,13 @@ default value is @code{0}, which disables any additional support on + Setting its value to @code{1} enables the use of @code{madvise} with + @code{MADV_HUGEPAGE} after memory allocation with @code{mmap}. It is enabled + only if the system supports Transparent Huge Page (currently only on Linux). ++ ++Setting its value to @code{2} enables the use of Huge Page directly with ++@code{mmap} with the use of @code{MAP_HUGETLB} flag. The huge page size ++to use will be the default one provided by the system. A value larger than ++@code{2} specifies huge page size, which will be matched against the system ++supported ones. If provided value is invalid, @code{MAP_HUGETLB} will not ++be used. + @end deftp + + @node Dynamic Linking Tunables +diff --git a/sysdeps/generic/malloc-hugepages.c b/sysdeps/generic/malloc-hugepages.c +index 8fb459a263..946284a33c 100644 +--- a/sysdeps/generic/malloc-hugepages.c ++++ b/sysdeps/generic/malloc-hugepages.c +@@ -29,3 +29,11 @@ __malloc_thp_mode (void) + { + return malloc_thp_mode_not_supported; + } ++ ++/* Return the default transparent huge page size. */ ++void ++__malloc_hugepage_config (size_t requested, size_t *pagesize, int *flags) ++{ ++ *pagesize = 0; ++ *flags = 0; ++} +diff --git a/sysdeps/generic/malloc-hugepages.h b/sysdeps/generic/malloc-hugepages.h +index f5a442e328..75cda3796a 100644 +--- a/sysdeps/generic/malloc-hugepages.h ++++ b/sysdeps/generic/malloc-hugepages.h +@@ -34,4 +34,11 @@ enum malloc_thp_mode_t + + enum malloc_thp_mode_t __malloc_thp_mode (void) attribute_hidden; + ++/* Return the supported huge page size from the REQUESTED sizes on PAGESIZE ++ along with the required extra mmap flags on FLAGS, Requesting the value ++ of 0 returns the default huge page size, otherwise the value will be ++ matched against the sizes supported by the system. */ ++void __malloc_hugepage_config (size_t requested, size_t *pagesize, int *flags) ++ attribute_hidden; ++ + #endif /* _MALLOC_HUGEPAGES_H */ +diff --git a/sysdeps/unix/sysv/linux/malloc-hugepages.c b/sysdeps/unix/sysv/linux/malloc-hugepages.c +index 7497e07260..0e05291d61 100644 +--- a/sysdeps/unix/sysv/linux/malloc-hugepages.c ++++ b/sysdeps/unix/sysv/linux/malloc-hugepages.c +@@ -17,8 +17,10 @@ + not, see . */ + + #include ++#include + #include + #include ++#include + + unsigned long int + __malloc_default_thp_pagesize (void) +@@ -72,3 +74,128 @@ __malloc_thp_mode (void) + } + return malloc_thp_mode_not_supported; + } ++ ++static size_t ++malloc_default_hugepage_size (void) ++{ ++ int fd = __open64_nocancel ("/proc/meminfo", O_RDONLY); ++ if (fd == -1) ++ return 0; ++ ++ size_t hpsize = 0; ++ ++ char buf[512]; ++ off64_t off = 0; ++ while (1) ++ { ++ ssize_t r = __pread64_nocancel (fd, buf, sizeof (buf) - 1, off); ++ if (r < 0) ++ break; ++ buf[r] = '\0'; ++ ++ /* If the tag is not found, read the last line again. */ ++ const char *s = strstr (buf, "Hugepagesize:"); ++ if (s == NULL) ++ { ++ char *nl = strrchr (buf, '\n'); ++ if (nl == NULL) ++ break; ++ off += (nl + 1) - buf; ++ continue; ++ } ++ ++ /* The default huge page size is in the form: ++ Hugepagesize: NUMBER kB */ ++ s += sizeof ("Hugepagesize: ") - 1; ++ for (int i = 0; (s[i] >= '0' && s[i] <= '9') || s[i] == ' '; i++) ++ { ++ if (s[i] == ' ') ++ continue; ++ hpsize *= 10; ++ hpsize += s[i] - '0'; ++ } ++ hpsize *= 1024; ++ break; ++ } ++ ++ __close_nocancel (fd); ++ ++ return hpsize; ++} ++ ++static inline int ++hugepage_flags (size_t pagesize) ++{ ++ return MAP_HUGETLB | (__builtin_ctzll (pagesize) << MAP_HUGE_SHIFT); ++} ++ ++void ++__malloc_hugepage_config (size_t requested, size_t *pagesize, int *flags) ++{ ++ *pagesize = 0; ++ *flags = 0; ++ ++ if (requested == 0) ++ { ++ *pagesize = malloc_default_hugepage_size (); ++ if (*pagesize != 0) ++ *flags = hugepage_flags (*pagesize); ++ return; ++ } ++ ++ /* Each entry represents a supported huge page in the form of: ++ hugepages-kB. */ ++ int dirfd = __open64_nocancel ("/sys/kernel/mm/hugepages", ++ O_RDONLY | O_DIRECTORY, 0); ++ if (dirfd == -1) ++ return; ++ ++ char buffer[1024]; ++ while (true) ++ { ++#if !IS_IN(libc) ++# define __getdents64 getdents64 ++#endif ++ ssize_t ret = __getdents64 (dirfd, buffer, sizeof (buffer)); ++ if (ret == -1) ++ break; ++ else if (ret == 0) ++ break; ++ ++ bool found = false; ++ char *begin = buffer, *end = buffer + ret; ++ while (begin != end) ++ { ++ unsigned short int d_reclen; ++ memcpy (&d_reclen, begin + offsetof (struct dirent64, d_reclen), ++ sizeof (d_reclen)); ++ const char *dname = begin + offsetof (struct dirent64, d_name); ++ begin += d_reclen; ++ ++ if (dname[0] == '.' ++ || strncmp (dname, "hugepages-", sizeof ("hugepages-") - 1) != 0) ++ continue; ++ ++ size_t hpsize = 0; ++ const char *sizestr = dname + sizeof ("hugepages-") - 1; ++ for (int i = 0; sizestr[i] >= '0' && sizestr[i] <= '9'; i++) ++ { ++ hpsize *= 10; ++ hpsize += sizestr[i] - '0'; ++ } ++ hpsize *= 1024; ++ ++ if (hpsize == requested) ++ { ++ *pagesize = hpsize; ++ *flags = hugepage_flags (*pagesize); ++ found = true; ++ break; ++ } ++ } ++ if (found) ++ break; ++ } ++ ++ __close_nocancel (dirfd); ++} +-- +2.33.0 + diff --git a/malloc-hugepage-0005-malloc-Add-Huge-Page-support-to-arenas.patch b/malloc-hugepage-0005-malloc-Add-Huge-Page-support-to-arenas.patch new file mode 100644 index 0000000000000000000000000000000000000000..f759588b0dc8cf464b9b2d5ede21e2e13bb8115a --- /dev/null +++ b/malloc-hugepage-0005-malloc-Add-Huge-Page-support-to-arenas.patch @@ -0,0 +1,338 @@ +From c1beb51d08d3d7ec935b0a2419b4c6fad91d1969 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Fri, 20 Aug 2021 13:22:35 -0300 +Subject: [PATCH 5/7] malloc: Add Huge Page support to arenas + +It is enabled as default for glibc.malloc.hugetlb set to 2 or higher. +It also uses a non configurable minimum value and maximum value, +currently set respectively to 1 and 4 selected huge page size. + +The arena allocation with huge pages does not use MAP_NORESERVE. As +indicate by kernel internal documentation [1], the flag might trigger +a SIGBUS on soft page faults if at memory access there is no left +pages in the pool. + +On systems without a reserved huge pages pool, is just stress the +mmap(MAP_HUGETLB) allocation failure. To improve test coverage it is +required to create a pool with some allocated pages. + +Checked on x86_64-linux-gnu with no reserved pages, 10 reserved pages +(which trigger mmap(MAP_HUGETBL) failures) and with 256 reserved pages +(which does not trigger mmap(MAP_HUGETLB) failures). + +[1] https://www.kernel.org/doc/html/v4.18/vm/hugetlbfs_reserv.html#resv-map-modifications + +Reviewed-by: DJ Delorie +--- + malloc/Makefile | 7 ++- + malloc/arena.c | 134 +++++++++++++++++++++++++++++++++--------------- + malloc/malloc.c | 2 +- + 3 files changed, 99 insertions(+), 44 deletions(-) + +diff --git a/malloc/Makefile b/malloc/Makefile +index e9a6666d22..451eb84612 100644 +--- a/malloc/Makefile ++++ b/malloc/Makefile +@@ -91,10 +91,15 @@ tests-exclude-hugetlb1 = \ + tst-malloc-usable \ + tst-malloc-usable-tunables \ + tst-mallocstate ++# The tst-free-errno relies on the used malloc page size to mmap an ++# overlapping region. ++tests-exclude-hugetlb2 = \ ++ $(tests-exclude-hugetlb1) \ ++ tst-free-errno + tests-malloc-hugetlb1 = \ + $(filter-out $(tests-exclude-hugetlb1), $(tests)) + tests-malloc-hugetlb2 = \ +- $(filter-out $(tests-exclude-hugetlb1), $(tests)) ++ $(filter-out $(tests-exclude-hugetlb2), $(tests)) + + # -lmcheck needs __malloc_initialize_hook, which was deprecated in 2.24. + ifeq ($(have-GLIBC_2.23)$(build-shared),yesyes) +diff --git a/malloc/arena.c b/malloc/arena.c +index 9a6e1af2bd..e1852f8597 100644 +--- a/malloc/arena.c ++++ b/malloc/arena.c +@@ -41,6 +41,29 @@ + mmap threshold, so that requests with a size just below that + threshold can be fulfilled without creating too many heaps. */ + ++/* When huge pages are used to create new arenas, the maximum and minumum ++ size are based on the runtime defined huge page size. */ ++ ++static inline size_t ++heap_min_size (void) ++{ ++#if HAVE_TUNABLES ++ return mp_.hp_pagesize == 0 ? HEAP_MIN_SIZE : mp_.hp_pagesize; ++#else ++ return HEAP_MIN_SIZE; ++#endif ++} ++ ++static inline size_t ++heap_max_size (void) ++{ ++#if HAVE_TUNABLES ++ return mp_.hp_pagesize == 0 ? HEAP_MAX_SIZE : mp_.hp_pagesize * 4; ++#else ++ return HEAP_MAX_SIZE; ++#endif ++} ++ + /***************************************************************************/ + + #define top(ar_ptr) ((ar_ptr)->top) +@@ -56,10 +79,11 @@ typedef struct _heap_info + size_t size; /* Current size in bytes. */ + size_t mprotect_size; /* Size in bytes that has been mprotected + PROT_READ|PROT_WRITE. */ ++ size_t pagesize; /* Page size used when allocating the arena. */ + /* Make sure the following data is properly aligned, particularly + that sizeof (heap_info) + 2 * SIZE_SZ is a multiple of + MALLOC_ALIGNMENT. */ +- char pad[-6 * SIZE_SZ & MALLOC_ALIGN_MASK]; ++ char pad[-3 * SIZE_SZ & MALLOC_ALIGN_MASK]; + } heap_info; + + /* Get a compile-time error if the heap_info padding is not correct +@@ -125,10 +149,18 @@ static bool __malloc_initialized = false; + + /* find the heap and corresponding arena for a given ptr */ + +-#define heap_for_ptr(ptr) \ +- ((heap_info *) ((unsigned long) (ptr) & ~(HEAP_MAX_SIZE - 1))) +-#define arena_for_chunk(ptr) \ +- (chunk_main_arena (ptr) ? &main_arena : heap_for_ptr (ptr)->ar_ptr) ++static inline heap_info * ++heap_for_ptr (void *ptr) ++{ ++ size_t max_size = heap_max_size (); ++ return PTR_ALIGN_DOWN (ptr, max_size); ++} ++ ++static inline struct malloc_state * ++arena_for_chunk (mchunkptr ptr) ++{ ++ return chunk_main_arena (ptr) ? &main_arena : heap_for_ptr (ptr)->ar_ptr; ++} + + + /**************************************************************************/ +@@ -443,71 +475,72 @@ static char *aligned_heap_area; + of the page size. */ + + static heap_info * +-new_heap (size_t size, size_t top_pad) ++alloc_new_heap (size_t size, size_t top_pad, size_t pagesize, ++ int mmap_flags) + { +- size_t pagesize = GLRO (dl_pagesize); + char *p1, *p2; + unsigned long ul; + heap_info *h; ++ size_t min_size = heap_min_size (); ++ size_t max_size = heap_max_size (); + +- if (size + top_pad < HEAP_MIN_SIZE) +- size = HEAP_MIN_SIZE; +- else if (size + top_pad <= HEAP_MAX_SIZE) ++ if (size + top_pad < min_size) ++ size = min_size; ++ else if (size + top_pad <= max_size) + size += top_pad; +- else if (size > HEAP_MAX_SIZE) ++ else if (size > max_size) + return 0; + else +- size = HEAP_MAX_SIZE; ++ size = max_size; + size = ALIGN_UP (size, pagesize); + +- /* A memory region aligned to a multiple of HEAP_MAX_SIZE is needed. ++ /* A memory region aligned to a multiple of max_size is needed. + No swap space needs to be reserved for the following large + mapping (on Linux, this is the case for all non-writable mappings + anyway). */ + p2 = MAP_FAILED; + if (aligned_heap_area) + { +- p2 = (char *) MMAP (aligned_heap_area, HEAP_MAX_SIZE, PROT_NONE, +- MAP_NORESERVE); ++ p2 = (char *) MMAP (aligned_heap_area, max_size, PROT_NONE, mmap_flags); + aligned_heap_area = NULL; +- if (p2 != MAP_FAILED && ((unsigned long) p2 & (HEAP_MAX_SIZE - 1))) ++ if (p2 != MAP_FAILED && ((unsigned long) p2 & (max_size - 1))) + { +- __munmap (p2, HEAP_MAX_SIZE); ++ __munmap (p2, max_size); + p2 = MAP_FAILED; + } + } + if (p2 == MAP_FAILED) + { +- p1 = (char *) MMAP (0, HEAP_MAX_SIZE << 1, PROT_NONE, MAP_NORESERVE); ++ p1 = (char *) MMAP (0, max_size << 1, PROT_NONE, mmap_flags); + if (p1 != MAP_FAILED) + { +- p2 = (char *) (((unsigned long) p1 + (HEAP_MAX_SIZE - 1)) +- & ~(HEAP_MAX_SIZE - 1)); ++ p2 = (char *) (((unsigned long) p1 + (max_size - 1)) ++ & ~(max_size - 1)); + ul = p2 - p1; + if (ul) + __munmap (p1, ul); + else +- aligned_heap_area = p2 + HEAP_MAX_SIZE; +- __munmap (p2 + HEAP_MAX_SIZE, HEAP_MAX_SIZE - ul); ++ aligned_heap_area = p2 + max_size; ++ __munmap (p2 + max_size, max_size - ul); + } + else + { +- /* Try to take the chance that an allocation of only HEAP_MAX_SIZE ++ /* Try to take the chance that an allocation of only max_size + is already aligned. */ +- p2 = (char *) MMAP (0, HEAP_MAX_SIZE, PROT_NONE, MAP_NORESERVE); ++ p2 = (char *) MMAP (0, max_size, PROT_NONE, mmap_flags); + if (p2 == MAP_FAILED) + return 0; + +- if ((unsigned long) p2 & (HEAP_MAX_SIZE - 1)) ++ if ((unsigned long) p2 & (max_size - 1)) + { +- __munmap (p2, HEAP_MAX_SIZE); ++ __munmap (p2, max_size); + return 0; + } + } + } + if (__mprotect (p2, size, mtag_mmap_flags | PROT_READ | PROT_WRITE) != 0) + { +- __munmap (p2, HEAP_MAX_SIZE); ++ __munmap (p2, max_size); + return 0; + } + +@@ -516,22 +549,42 @@ new_heap (size_t size, size_t top_pad) + h = (heap_info *) p2; + h->size = size; + h->mprotect_size = size; ++ h->pagesize = pagesize; + LIBC_PROBE (memory_heap_new, 2, h, h->size); + return h; + } + ++static heap_info * ++new_heap (size_t size, size_t top_pad) ++{ ++#if HAVE_TUNABLES ++ if (__glibc_unlikely (mp_.hp_pagesize != 0)) ++ { ++ /* MAP_NORESERVE is not used for huge pages because some kernel may ++ not reserve the mmap region and a subsequent access may trigger ++ a SIGBUS if there is no free pages in the pool. */ ++ heap_info *h = alloc_new_heap (size, top_pad, mp_.hp_pagesize, ++ mp_.hp_flags); ++ if (h != NULL) ++ return h; ++ } ++#endif ++ return alloc_new_heap (size, top_pad, GLRO (dl_pagesize), MAP_NORESERVE); ++} ++ + /* Grow a heap. size is automatically rounded up to a + multiple of the page size. */ + + static int + grow_heap (heap_info *h, long diff) + { +- size_t pagesize = GLRO (dl_pagesize); ++ size_t pagesize = h->pagesize; ++ size_t max_size = heap_max_size (); + long new_size; + + diff = ALIGN_UP (diff, pagesize); + new_size = (long) h->size + diff; +- if ((unsigned long) new_size > (unsigned long) HEAP_MAX_SIZE) ++ if ((unsigned long) new_size > (unsigned long) max_size) + return -1; + + if ((unsigned long) new_size > h->mprotect_size) +@@ -581,21 +634,14 @@ shrink_heap (heap_info *h, long diff) + + /* Delete a heap. */ + +-#define delete_heap(heap) \ +- do { \ +- if ((char *) (heap) + HEAP_MAX_SIZE == aligned_heap_area) \ +- aligned_heap_area = NULL; \ +- __munmap ((char *) (heap), HEAP_MAX_SIZE); \ +- } while (0) +- + static int + heap_trim (heap_info *heap, size_t pad) + { + mstate ar_ptr = heap->ar_ptr; +- unsigned long pagesz = GLRO (dl_pagesize); + mchunkptr top_chunk = top (ar_ptr), p; + heap_info *prev_heap; + long new_size, top_size, top_area, extra, prev_size, misalign; ++ size_t max_size = heap_max_size (); + + /* Can this heap go away completely? */ + while (top_chunk == chunk_at_offset (heap, sizeof (*heap))) +@@ -612,19 +658,23 @@ heap_trim (heap_info *heap, size_t pad) + assert (new_size > 0 && new_size < (long) (2 * MINSIZE)); + if (!prev_inuse (p)) + new_size += prev_size (p); +- assert (new_size > 0 && new_size < HEAP_MAX_SIZE); +- if (new_size + (HEAP_MAX_SIZE - prev_heap->size) < pad + MINSIZE + pagesz) ++ assert (new_size > 0 && new_size < max_size); ++ if (new_size + (max_size - prev_heap->size) < pad + MINSIZE ++ + heap->pagesize) + break; + ar_ptr->system_mem -= heap->size; + LIBC_PROBE (memory_heap_free, 2, heap, heap->size); +- delete_heap (heap); ++ if ((char *) heap + max_size == aligned_heap_area) ++ aligned_heap_area = NULL; ++ __munmap (heap, max_size); + heap = prev_heap; + if (!prev_inuse (p)) /* consolidate backward */ + { + p = prev_chunk (p); + unlink_chunk (ar_ptr, p); + } +- assert (((unsigned long) ((char *) p + new_size) & (pagesz - 1)) == 0); ++ assert (((unsigned long) ((char *) p + new_size) & (heap->pagesize - 1)) ++ == 0); + assert (((char *) p + new_size) == ((char *) heap + heap->size)); + top (ar_ptr) = top_chunk = p; + set_head (top_chunk, new_size | PREV_INUSE); +@@ -644,7 +694,7 @@ heap_trim (heap_info *heap, size_t pad) + return 0; + + /* Release in pagesize units and round down to the nearest page. */ +- extra = ALIGN_DOWN(top_area - pad, pagesz); ++ extra = ALIGN_DOWN(top_area - pad, heap->pagesize); + if (extra == 0) + return 0; + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 75efdc2ee7..1698d45d1e 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -5302,7 +5302,7 @@ static __always_inline int + do_set_mmap_threshold (size_t value) + { + /* Forbid setting the threshold too high. */ +- if (value <= HEAP_MAX_SIZE / 2) ++ if (value <= heap_max_size () / 2) + { + LIBC_PROBE (memory_mallopt_mmap_threshold, 3, value, mp_.mmap_threshold, + mp_.no_dyn_threshold); +-- +2.33.0 + diff --git a/malloc-hugepage-0006-malloc-Move-MORECORE-fallback-mmap-to-sysmalloc_mmap.patch b/malloc-hugepage-0006-malloc-Move-MORECORE-fallback-mmap-to-sysmalloc_mmap.patch new file mode 100644 index 0000000000000000000000000000000000000000..afc5650dab234c6ac8adf184654b694a35c5e51d --- /dev/null +++ b/malloc-hugepage-0006-malloc-Move-MORECORE-fallback-mmap-to-sysmalloc_mmap.patch @@ -0,0 +1,119 @@ +From 0849eed45daabf30a02c153695041597d6d43b2d Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Mon, 30 Aug 2021 10:56:55 -0300 +Subject: [PATCH 6/7] malloc: Move MORECORE fallback mmap to + sysmalloc_mmap_fallback + +So it can be used on hugepage code as well. + +Reviewed-by: DJ Delorie +--- + malloc/malloc.c | 85 ++++++++++++++++++++++++++++++------------------- + 1 file changed, 53 insertions(+), 32 deletions(-) + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 1698d45d1e..32050be4cc 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -2498,6 +2498,51 @@ sysmalloc_mmap (INTERNAL_SIZE_T nb, size_t pagesize, int extra_flags, mstate av) + return chunk2mem (p); + } + ++/* ++ Allocate memory using mmap() based on S and NB requested size, aligning to ++ PAGESIZE if required. The EXTRA_FLAGS is used on mmap() call. If the call ++ succeedes S is updated with the allocated size. This is used as a fallback ++ if MORECORE fails. ++ */ ++static void * ++sysmalloc_mmap_fallback (long int *s, INTERNAL_SIZE_T nb, ++ INTERNAL_SIZE_T old_size, size_t minsize, ++ size_t pagesize, int extra_flags, mstate av) ++{ ++ long int size = *s; ++ ++ /* Cannot merge with old top, so add its size back in */ ++ if (contiguous (av)) ++ size = ALIGN_UP (size + old_size, pagesize); ++ ++ /* If we are relying on mmap as backup, then use larger units */ ++ if ((unsigned long) (size) < minsize) ++ size = minsize; ++ ++ /* Don't try if size wraps around 0 */ ++ if ((unsigned long) (size) <= (unsigned long) (nb)) ++ return MORECORE_FAILURE; ++ ++ char *mbrk = (char *) (MMAP (0, size, ++ mtag_mmap_flags | PROT_READ | PROT_WRITE, ++ extra_flags)); ++ if (mbrk == MAP_FAILED) ++ return MAP_FAILED; ++ ++#ifdef MAP_HUGETLB ++ if (!(extra_flags & MAP_HUGETLB)) ++ madvise_thp (mbrk, size); ++#endif ++ ++ /* Record that we no longer have a contiguous sbrk region. After the first ++ time mmap is used as backup, we do not ever rely on contiguous space ++ since this could incorrectly bridge regions. */ ++ set_noncontiguous (av); ++ ++ *s = size; ++ return mbrk; ++} ++ + static void * + sysmalloc (INTERNAL_SIZE_T nb, mstate av) + { +@@ -2696,38 +2741,14 @@ sysmalloc (INTERNAL_SIZE_T nb, mstate av) + segregated mmap region. + */ + +- /* Cannot merge with old top, so add its size back in */ +- if (contiguous (av)) +- size = ALIGN_UP (size + old_size, pagesize); +- +- /* If we are relying on mmap as backup, then use larger units */ +- if ((unsigned long) (size) < (unsigned long) (MMAP_AS_MORECORE_SIZE)) +- size = MMAP_AS_MORECORE_SIZE; +- +- /* Don't try if size wraps around 0 */ +- if ((unsigned long) (size) > (unsigned long) (nb)) +- { +- char *mbrk = (char *) (MMAP (0, size, +- mtag_mmap_flags | PROT_READ | PROT_WRITE, +- 0)); +- +- if (mbrk != MAP_FAILED) +- { +- madvise_thp (mbrk, size); +- +- /* We do not need, and cannot use, another sbrk call to find end */ +- brk = mbrk; +- snd_brk = brk + size; +- +- /* +- Record that we no longer have a contiguous sbrk region. +- After the first time mmap is used as backup, we do not +- ever rely on contiguous space since this could incorrectly +- bridge regions. +- */ +- set_noncontiguous (av); +- } +- } ++ char *mbrk = sysmalloc_mmap_fallback (&size, nb, old_size, pagesize, ++ MMAP_AS_MORECORE_SIZE, 0, av); ++ if (mbrk != MAP_FAILED) ++ { ++ /* We do not need, and cannot use, another sbrk call to find end */ ++ brk = mbrk; ++ snd_brk = brk + size; ++ } + } + + if (brk != (char *) (MORECORE_FAILURE)) +-- +2.33.0 + diff --git a/malloc-hugepage-0007-malloc-Enable-huge-page-support-on-main-arena.patch b/malloc-hugepage-0007-malloc-Enable-huge-page-support-on-main-arena.patch new file mode 100644 index 0000000000000000000000000000000000000000..fa5c9db43787173aa477ffdf193abc2385c9692f --- /dev/null +++ b/malloc-hugepage-0007-malloc-Enable-huge-page-support-on-main-arena.patch @@ -0,0 +1,86 @@ +From 0f982c182760bd7689769ee7590df592d0a132c0 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Mon, 30 Aug 2021 14:01:00 -0300 +Subject: [PATCH 7/7] malloc: Enable huge page support on main arena + +This patch adds support huge page support on main arena allocation, +enable with tunable glibc.malloc.hugetlb=2. The patch essentially +disable the __glibc_morecore() sbrk() call (similar when memory +tag does when sbrk() call does not support it) and fallback to +default page size if the memory allocation fails. + +Checked on x86_64-linux-gnu. + +Reviewed-by: DJ Delorie +--- + malloc/arena.c | 4 ++++ + malloc/malloc.c | 12 ++++++++++-- + malloc/morecore.c | 4 ---- + 3 files changed, 14 insertions(+), 6 deletions(-) + +diff --git a/malloc/arena.c b/malloc/arena.c +index e1852f8597..3ed4ef3f05 100644 +--- a/malloc/arena.c ++++ b/malloc/arena.c +@@ -364,6 +364,10 @@ ptmalloc_init (void) + # endif + TUNABLE_GET (mxfast, size_t, TUNABLE_CALLBACK (set_mxfast)); + TUNABLE_GET (hugetlb, size_t, TUNABLE_CALLBACK (set_hugetlb)); ++ if (mp_.hp_pagesize > 0) ++ /* Force mmap for main arena instead of sbrk, so hugepages are explicitly ++ used. */ ++ __always_fail_morecore = true; + #else + if (__glibc_likely (_environ != NULL)) + { +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 32050be4cc..b67f2c84ee 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -2741,8 +2741,16 @@ sysmalloc (INTERNAL_SIZE_T nb, mstate av) + segregated mmap region. + */ + +- char *mbrk = sysmalloc_mmap_fallback (&size, nb, old_size, pagesize, +- MMAP_AS_MORECORE_SIZE, 0, av); ++ char *mbrk = MAP_FAILED; ++#if HAVE_TUNABLES ++ if (mp_.hp_pagesize > 0) ++ mbrk = sysmalloc_mmap_fallback (&size, nb, old_size, ++ mp_.hp_pagesize, mp_.hp_pagesize, ++ mp_.hp_flags, av); ++#endif ++ if (mbrk == MAP_FAILED) ++ mbrk = sysmalloc_mmap_fallback (&size, nb, old_size, pagesize, ++ MMAP_AS_MORECORE_SIZE, 0, av); + if (mbrk != MAP_FAILED) + { + /* We do not need, and cannot use, another sbrk call to find end */ +diff --git a/malloc/morecore.c b/malloc/morecore.c +index 8168ef158c..004cd3ead4 100644 +--- a/malloc/morecore.c ++++ b/malloc/morecore.c +@@ -15,9 +15,7 @@ + License along with the GNU C Library; if not, see + . */ + +-#if defined(SHARED) || defined(USE_MTAG) + static bool __always_fail_morecore = false; +-#endif + + /* Allocate INCREMENT more bytes of data space, + and return the start of data space, or NULL on errors. +@@ -25,10 +23,8 @@ static bool __always_fail_morecore = false; + void * + __glibc_morecore (ptrdiff_t increment) + { +-#if defined(SHARED) || defined(USE_MTAG) + if (__always_fail_morecore) + return NULL; +-#endif + + void *result = (void *) __sbrk (increment); + if (result == (void *) -1) +-- +2.33.0 + diff --git a/malloc-use-__get_nprocs-replace-__get_nprocs_sched.patch b/malloc-use-__get_nprocs-replace-__get_nprocs_sched.patch new file mode 100644 index 0000000000000000000000000000000000000000..d5aa11101bb475a53c7c72b527e4aa25adf469b4 --- /dev/null +++ b/malloc-use-__get_nprocs-replace-__get_nprocs_sched.patch @@ -0,0 +1,25 @@ +From f5545d74d6dc4d5036bee6a91cda14a51e2a0676 Mon Sep 17 00:00:00 2001 +From: Yang Yanchao +Date: Sat, 12 Mar 2022 15:30:17 +0800 +Subject: [PATCH] malloc: use __get_nprocs replace __get_nprocs_sched. + +--- + malloc/arena.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/malloc/arena.c b/malloc/arena.c +index f1f0af86..66748463 100644 +--- a/malloc/arena.c ++++ b/malloc/arena.c +@@ -879,7 +879,7 @@ arena_get2 (size_t size, mstate avoid_arena) + narenas_limit = mp_.arena_max; + else if (narenas > mp_.arena_test) + { +- int n = __get_nprocs_sched (); ++ int n = __get_nprocs (); + + if (n >= 1) + narenas_limit = NARENAS_FROM_NCORES (n); +-- +2.33.0 + diff --git a/misc-Add-__get_nprocs_sched.patch b/misc-Add-__get_nprocs_sched.patch new file mode 100644 index 0000000000000000000000000000000000000000..68e1208c751fb2a38709b900d4b6fb3f2acc11b5 --- /dev/null +++ b/misc-Add-__get_nprocs_sched.patch @@ -0,0 +1,110 @@ +From e870aac8974cda746157a5a3c9f452ccd70da29b Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Mon, 6 Sep 2021 12:22:54 -0300 +Subject: [PATCH] misc: Add __get_nprocs_sched + +This is an internal function meant to return the number of avaliable +processor where the process can scheduled, different than the +__get_nprocs which returns a the system available online CPU. + +The Linux implementation currently only calls __get_nprocs(), which +in tuns calls sched_getaffinity. + +Reviewed-by: Florian Weimer +(cherry picked from commit 11a02b035b464ab6813676adfd19c4a59c36d907) +--- + include/sys/sysinfo.h | 7 ++++++- + malloc/arena.c | 2 +- + misc/getsysstats.c | 6 ++++++ + sysdeps/mach/getsysstats.c | 6 ++++++ + sysdeps/unix/sysv/linux/getsysstats.c | 6 ++++++ + 5 files changed, 25 insertions(+), 2 deletions(-) + +diff --git a/include/sys/sysinfo.h b/include/sys/sysinfo.h +index 7388356..c490561 100644 +--- a/include/sys/sysinfo.h ++++ b/include/sys/sysinfo.h +@@ -9,10 +9,15 @@ + extern int __get_nprocs_conf (void); + libc_hidden_proto (__get_nprocs_conf) + +-/* Return number of available processors. */ ++/* Return number of available processors (not all of them will be ++ available to the caller process). */ + extern int __get_nprocs (void); + libc_hidden_proto (__get_nprocs) + ++/* Return the number of available processors which the process can ++ be scheduled. */ ++extern int __get_nprocs_sched (void) attribute_hidden; ++ + /* Return number of physical pages of memory in the system. */ + extern long int __get_phys_pages (void); + libc_hidden_proto (__get_phys_pages) +diff --git a/malloc/arena.c b/malloc/arena.c +index 6674846..f1f0af8 100644 +--- a/malloc/arena.c ++++ b/malloc/arena.c +@@ -879,7 +879,7 @@ arena_get2 (size_t size, mstate avoid_arena) + narenas_limit = mp_.arena_max; + else if (narenas > mp_.arena_test) + { +- int n = __get_nprocs (); ++ int n = __get_nprocs_sched (); + + if (n >= 1) + narenas_limit = NARENAS_FROM_NCORES (n); +diff --git a/misc/getsysstats.c b/misc/getsysstats.c +index 0eedfac..57d9360 100644 +--- a/misc/getsysstats.c ++++ b/misc/getsysstats.c +@@ -45,6 +45,12 @@ weak_alias (__get_nprocs, get_nprocs) + link_warning (get_nprocs, "warning: get_nprocs will always return 1") + + ++int ++__get_nprocs_sched (void) ++{ ++ return 1; ++} ++ + long int + __get_phys_pages (void) + { +diff --git a/sysdeps/mach/getsysstats.c b/sysdeps/mach/getsysstats.c +index 1267f39..cc8023f 100644 +--- a/sysdeps/mach/getsysstats.c ++++ b/sysdeps/mach/getsysstats.c +@@ -62,6 +62,12 @@ __get_nprocs (void) + libc_hidden_def (__get_nprocs) + weak_alias (__get_nprocs, get_nprocs) + ++int ++__get_nprocs_sched (void) ++{ ++ return __get_nprocs (); ++} ++ + /* Return the number of physical pages on the system. */ + long int + __get_phys_pages (void) +diff --git a/sysdeps/unix/sysv/linux/getsysstats.c b/sysdeps/unix/sysv/linux/getsysstats.c +index 1391e36..120ce1b 100644 +--- a/sysdeps/unix/sysv/linux/getsysstats.c ++++ b/sysdeps/unix/sysv/linux/getsysstats.c +@@ -88,6 +88,12 @@ __get_nprocs (void) + libc_hidden_def (__get_nprocs) + weak_alias (__get_nprocs, get_nprocs) + ++int ++__get_nprocs_sched (void) ++{ ++ return __get_nprocs (); ++} ++ + + /* On some architectures it is possible to distinguish between configured + and active cpus. */ +-- +1.8.3.1 + diff --git a/mtrace-Fix-output-with-PIE-and-ASLR-BZ-22716.patch b/mtrace-Fix-output-with-PIE-and-ASLR-BZ-22716.patch new file mode 100644 index 0000000000000000000000000000000000000000..10622da623b013f68f8975c09485d0a00d6b0242 --- /dev/null +++ b/mtrace-Fix-output-with-PIE-and-ASLR-BZ-22716.patch @@ -0,0 +1,77 @@ +From f2e33c3268db9adf8e57e991676ed0d5ac74e8a8 Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +Date: Mon, 23 Aug 2021 08:11:54 +0530 +Subject: [PATCH] mtrace: Fix output with PIE and ASLR [BZ #22716] + +Record only the relative address of the caller in mtrace file. Use +LD_TRACE_PRELINKING to get the executable as well as binary vs +executable load offsets so that we may compute a base to add to the +relative address in the mtrace file. This allows us to get a valid +address to pass to addr2line in all cases. + +Fixes BZ #22716. + +Co-authored-by: John Ogness +Reviewed-by: Andreas Schwab +Reviewed-by: DJ Delorie +--- + malloc/mtrace-impl.c | 6 +++--- + malloc/mtrace.pl | 15 +++++++-------- + 2 files changed, 10 insertions(+), 11 deletions(-) + +diff --git a/malloc/mtrace-impl.c b/malloc/mtrace-impl.c +index 83008ca..f5f19c2 100644 +--- a/malloc/mtrace-impl.c ++++ b/malloc/mtrace-impl.c +@@ -65,9 +65,9 @@ tr_where (const void *caller, Dl_info *info) + offset); + } + +- fprintf (mallstream, "@ %s%s%s[%p] ", info->dli_fname ? : "", +- info->dli_fname ? ":" : "", +- buf, caller); ++ fprintf (mallstream, "@ %s%s%s[0x%" PRIxPTR "] ", ++ info->dli_fname ? : "", info->dli_fname ? ":" : "", buf, ++ caller - info->dli_fbase); + } + else + fprintf (mallstream, "@ [%p] ", caller); +diff --git a/malloc/mtrace.pl b/malloc/mtrace.pl +index 6f49c83..b1073a1 100644 +--- a/malloc/mtrace.pl ++++ b/malloc/mtrace.pl +@@ -75,11 +75,15 @@ if ($#ARGV == 0) { + } else { + $prog = "./$binary"; + } +- if (open (LOCS, "env LD_TRACE_LOADED_OBJECTS=1 $prog |")) { ++ # Set the environment variable LD_TRACE_PRELINKING to an empty string so ++ # that we trigger tracing but do not match with the executable or any of ++ # its dependencies. ++ if (open (LOCS, "env LD_TRACE_PRELINKING= $prog |")) { + while () { + chop; +- if (/^.*=> (.*) .(0x[0123456789abcdef]*).$/) { ++ if (/^.*=> (.*) \((0x[0123456789abcdef]*), (0x[0123456789abcdef]*).*/) { + $locs{$1} = $2; ++ $rel{$1} = hex($2) - hex($3); + } + } + close (LOCS); +@@ -110,12 +114,7 @@ sub location { + my $addr = $2; + my $searchaddr; + return $cache{$addr} if (exists $cache{$addr}); +- if ($locs{$prog} ne "") { +- $searchaddr = sprintf "%#x", $addr - $locs{$prog}; +- } else { +- $searchaddr = $addr; +- $prog = $binary; +- } ++ $searchaddr = sprintf "%#x", hex($addr) + $rel{$prog}; + if ($binary ne "" && open (ADDR, "addr2line -e $prog $searchaddr|")) { + my $line = ; + chomp $line; +-- +1.8.3.1 + diff --git a/mtrace-Use-a-static-buffer-for-printing-BZ-25947.patch b/mtrace-Use-a-static-buffer-for-printing-BZ-25947.patch new file mode 100644 index 0000000000000000000000000000000000000000..9c25d437166403be1a65a8d6acd48b7c62659215 --- /dev/null +++ b/mtrace-Use-a-static-buffer-for-printing-BZ-25947.patch @@ -0,0 +1,61 @@ +From dc906e94f7033892dadbd91718349f19e1376391 Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +Date: Thu, 12 Aug 2021 06:38:15 +0530 +Subject: [PATCH] mtrace: Use a static buffer for printing [BZ #25947] + +Use a static buffer for mtrace printing now that it no longer adds to +default libc footprint. + +Reviewed-by: DJ Delorie +--- + malloc/mtrace-impl.c | 14 +++----------- + 1 file changed, 3 insertions(+), 11 deletions(-) + +diff --git a/malloc/mtrace-impl.c b/malloc/mtrace-impl.c +index 0e10ab7..83008ca 100644 +--- a/malloc/mtrace-impl.c ++++ b/malloc/mtrace-impl.c +@@ -34,11 +34,8 @@ + + #include + +-#define TRACE_BUFFER_SIZE 512 +- + static FILE *mallstream; + static const char mallenv[] = "MALLOC_TRACE"; +-static char *malloc_trace_buffer; + + static void + tr_where (const void *caller, Dl_info *info) +@@ -184,16 +181,13 @@ do_mtrace (void) + mallfile = secure_getenv (mallenv); + if (mallfile != NULL) + { +- char *mtb = malloc (TRACE_BUFFER_SIZE); +- if (mtb == NULL) +- return; +- + mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wce"); + if (mallstream != NULL) + { + /* Be sure it doesn't malloc its buffer! */ +- malloc_trace_buffer = mtb; +- setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE); ++ static char tracebuf [512]; ++ ++ setvbuf (mallstream, tracebuf, _IOFBF, sizeof (tracebuf)); + fprintf (mallstream, "= Start\n"); + if (!added_atexit_handler) + { +@@ -203,8 +197,6 @@ do_mtrace (void) + } + __malloc_debug_enable (MALLOC_MTRACE_HOOK); + } +- else +- free (mtb); + } + } + +-- +1.8.3.1 + diff --git a/nis-Fix-leak-on-realloc-failure-in-nis_getnames-BZ-2.patch b/nis-Fix-leak-on-realloc-failure-in-nis_getnames-BZ-2.patch new file mode 100644 index 0000000000000000000000000000000000000000..b72b47476112e7583629e61aeada649eadf423d2 --- /dev/null +++ b/nis-Fix-leak-on-realloc-failure-in-nis_getnames-BZ-2.patch @@ -0,0 +1,46 @@ +From 60698263122b7c54ded3f70a466176e17a529480 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Wed, 28 Jul 2021 14:23:32 -0400 +Subject: [PATCH] nis: Fix leak on realloc failure in nis_getnames [BZ #28150] + +If pos >= count but realloc fails, tmp will not have been placed in +getnames[pos] yet, and so will not be freed in free_null. Detected +by Coverity. + +Also remove misleading comment from nis_getnames(), since it actually +did properly release getnames when out of memory. + +Tested-by: Carlos O'Donell +--- + nis/nis_subr.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/nis/nis_subr.c b/nis/nis_subr.c +index dd0e300..6784fc3 100644 +--- a/nis/nis_subr.c ++++ b/nis/nis_subr.c +@@ -103,9 +103,6 @@ count_dots (const_nis_name str) + return count; + } + +-/* If we run out of memory, we don't give already allocated memory +- free. The overhead for bringing getnames back in a safe state to +- free it is to big. */ + nis_name * + nis_getnames (const_nis_name name) + { +@@ -271,7 +268,10 @@ nis_getnames (const_nis_name name) + nis_name *newp = realloc (getnames, + (count + 1) * sizeof (char *)); + if (__glibc_unlikely (newp == NULL)) +- goto free_null; ++ { ++ free (tmp); ++ goto free_null; ++ } + getnames = newp; + } + getnames[pos] = tmp; +-- +1.8.3.1 + diff --git a/nptl-Add-one-more-barrier-to-nptl-tst-create1.patch b/nptl-Add-one-more-barrier-to-nptl-tst-create1.patch new file mode 100644 index 0000000000000000000000000000000000000000..e18a8bc16f10c229f285c799530b66c5fcd119fe --- /dev/null +++ b/nptl-Add-one-more-barrier-to-nptl-tst-create1.patch @@ -0,0 +1,67 @@ +From 5cc338565479a620244c2f8ff35956629c4dbf81 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 10 Dec 2021 05:14:24 +0100 +Subject: [PATCH] nptl: Add one more barrier to nptl/tst-create1 + +Without the bar_ctor_finish barrier, it was possible that thread2 +re-locked user_lock before ctor had a chance to lock it. ctor then +blocked in its locking operation, xdlopen from the main thread +did not return, and thread2 was stuck waiting in bar_dtor: + +thread 1: started. +thread 2: started. +thread 2: locked user_lock. +constructor started: 0. +thread 1: in ctor: started. +thread 3: started. +thread 3: done. +thread 2: unlocked user_lock. +thread 2: locked user_lock. + +Fixes the test in commit 83b5323261bb72313bffcf37476c1b8f0847c736 +("elf: Avoid deadlock between pthread_create and ctors [BZ #28357]"). + +Reviewed-by: Szabolcs Nagy +--- + sysdeps/pthread/tst-create1.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/sysdeps/pthread/tst-create1.c b/sysdeps/pthread/tst-create1.c +index 932586c..763ded8 100644 +--- a/sysdeps/pthread/tst-create1.c ++++ b/sysdeps/pthread/tst-create1.c +@@ -33,6 +33,7 @@ thread 2: lock(user_lock) -> pthread_create + */ + + static pthread_barrier_t bar_ctor; ++static pthread_barrier_t bar_ctor_finish; + static pthread_barrier_t bar_dtor; + static pthread_mutex_t user_lock = PTHREAD_MUTEX_INITIALIZER; + +@@ -46,6 +47,7 @@ ctor (void) + xpthread_mutex_unlock (&user_lock); + dprintf (1, "thread 1: in ctor: unlocked user_lock.\n"); + dprintf (1, "thread 1: in ctor: done.\n"); ++ xpthread_barrier_wait (&bar_ctor_finish); + } + + void +@@ -81,6 +83,7 @@ thread2 (void *a) + xpthread_mutex_unlock (&user_lock); + dprintf (1, "thread 2: unlocked user_lock.\n"); + xpthread_join (t3); ++ xpthread_barrier_wait (&bar_ctor_finish); + + xpthread_mutex_lock (&user_lock); + dprintf (1, "thread 2: locked user_lock.\n"); +@@ -99,6 +102,7 @@ thread1 (void) + { + dprintf (1, "thread 1: started.\n"); + xpthread_barrier_init (&bar_ctor, NULL, 2); ++ xpthread_barrier_init (&bar_ctor_finish, NULL, 2); + xpthread_barrier_init (&bar_dtor, NULL, 2); + pthread_t t2 = xpthread_create (0, thread2, 0); + void *p = xdlopen ("tst-create1mod.so", RTLD_NOW | RTLD_GLOBAL); +-- +1.8.3.1 + diff --git a/nptl-Avoid-setxid-deadlock-with-blocked-signals-in-t.patch b/nptl-Avoid-setxid-deadlock-with-blocked-signals-in-t.patch new file mode 100644 index 0000000000000000000000000000000000000000..e582b7042189d3a23db9ff767379e51cfdd56386 --- /dev/null +++ b/nptl-Avoid-setxid-deadlock-with-blocked-signals-in-t.patch @@ -0,0 +1,137 @@ +From 2849e2f53311b66853cb5159b64cba2bddbfb854 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Thu, 23 Sep 2021 09:55:54 +0200 +Subject: [PATCH] nptl: Avoid setxid deadlock with blocked signals in thread + exit [BZ #28361] + +As part of the fix for bug 12889, signals are blocked during +thread exit, so that application code cannot run on the thread that +is about to exit. This would cause problems if the application +expected signals to be delivered after the signal handler revealed +the thread to still exist, despite pthread_kill can no longer be used +to send signals to it. However, glibc internally uses the SIGSETXID +signal in a way that is incompatible with signal blocking, due to the +way the setxid handshake delays thread exit until the setxid operation +has completed. With a blocked SIGSETXID, the handshake can never +complete, causing a deadlock. + +As a band-aid, restore the previous handshake protocol by not blocking +SIGSETXID during thread exit. + +The new test sysdeps/pthread/tst-pthread-setuid-loop.c is based on +a downstream test by Martin Osvald. + +Reviewed-by: Carlos O'Donell +Tested-by: Carlos O'Donell +--- + nptl/pthread_create.c | 12 +++++- + sysdeps/pthread/Makefile | 1 + + sysdeps/pthread/tst-pthread-setuid-loop.c | 61 +++++++++++++++++++++++++++++++ + 3 files changed, 72 insertions(+), 2 deletions(-) + create mode 100644 sysdeps/pthread/tst-pthread-setuid-loop.c + +diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c +index a559f86..d6ea43a 100644 +--- a/nptl/pthread_create.c ++++ b/nptl/pthread_create.c +@@ -487,8 +487,16 @@ start_thread (void *arg) + + /* This prevents sending a signal from this thread to itself during + its final stages. This must come after the exit call above +- because atexit handlers must not run with signals blocked. */ +- __libc_signal_block_all (NULL); ++ because atexit handlers must not run with signals blocked. ++ ++ Do not block SIGSETXID. The setxid handshake below expects the ++ signal to be delivered. (SIGSETXID cannot run application code, ++ nor does it use pthread_kill.) Reuse the pd->sigmask space for ++ computing the signal mask, to save stack space. */ ++ __sigfillset (&pd->sigmask); ++ __sigdelset (&pd->sigmask, SIGSETXID); ++ INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_BLOCK, &pd->sigmask, NULL, ++ __NSIG_BYTES); + + /* Tell __pthread_kill_internal that this thread is about to exit. + If there is a __pthread_kill_internal in progress, this delays +diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile +index 48dba71..d4bd2d4 100644 +--- a/sysdeps/pthread/Makefile ++++ b/sysdeps/pthread/Makefile +@@ -118,6 +118,7 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ + tst-unload \ + tst-unwind-thread \ + tst-pt-vfork1 tst-pt-vfork2 tst-vfork1x tst-vfork2x \ ++ tst-pthread-setuid-loop \ + tst-pthread_cancel-exited \ + tst-pthread_cancel-select-loop \ + tst-pthread_kill-exited \ +diff --git a/sysdeps/pthread/tst-pthread-setuid-loop.c b/sysdeps/pthread/tst-pthread-setuid-loop.c +new file mode 100644 +index 0000000..fda2a49 +--- /dev/null ++++ b/sysdeps/pthread/tst-pthread-setuid-loop.c +@@ -0,0 +1,61 @@ ++/* Test that setuid, pthread_create, thread exit do not deadlock (bug 28361). ++ 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 ++ . */ ++ ++#include ++#include ++#include ++ ++/* How many threads to launch during each iteration. */ ++enum { threads = 4 }; ++ ++/* How many iterations to perform. This value seems to reproduce ++ bug 28361 in a bout one in three runs. */ ++enum { iterations = 5000 }; ++ ++/* Cache of the real user ID used by setuid_thread. */ ++static uid_t uid; ++ ++/* Start routine for the threads. */ ++static void * ++setuid_thread (void *closure) ++{ ++ TEST_COMPARE (setuid (uid), 0); ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ /* The setxid machinery is still invoked even if the UID is ++ unchanged. (The kernel might reset other credentials as part of ++ the system call.) */ ++ uid = getuid (); ++ ++ for (int i = 0; i < iterations; ++i) ++ { ++ pthread_t thread_ids[threads]; ++ for (int j = 0; j < threads; ++j) ++ thread_ids[j] = xpthread_create (NULL, setuid_thread, NULL); ++ for (int j = 0; j < threads; ++j) ++ xpthread_join (thread_ids[j]); ++ } ++ ++ return 0; ++} ++ ++#include +-- +1.8.3.1 + diff --git a/nptl-Do-not-set-signal-mask-on-second-setjmp-return-.patch b/nptl-Do-not-set-signal-mask-on-second-setjmp-return-.patch new file mode 100644 index 0000000000000000000000000000000000000000..8f5a571690f7ffec7a75d51bd82854468202093c --- /dev/null +++ b/nptl-Do-not-set-signal-mask-on-second-setjmp-return-.patch @@ -0,0 +1,111 @@ +From bfe68fe3c475fe34bed4e017d6e63196c305c934 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Wed, 24 Nov 2021 08:59:54 +0100 +Subject: [PATCH] nptl: Do not set signal mask on second setjmp return [BZ + #28607] + +__libc_signal_restore_set was in the wrong place: It also ran +when setjmp returned the second time (after pthread_exit or +pthread_cancel). This is observable with blocked pending +signals during thread exit. + +Fixes commit b3cae39dcbfa2432b3f3aa28854d8ac57f0de1b8 +("nptl: Start new threads with all signals blocked [BZ #25098]"). + +Reviewed-by: Adhemerval Zanella +(cherry picked from commit e186fc5a31e46f2cbf5ea1a75223b4412907f3d8) +--- + nptl/pthread_create.c | 4 +-- + sysdeps/pthread/Makefile | 1 + + sysdeps/pthread/tst-pthread-exit-signal.c | 45 +++++++++++++++++++++++++++++++ + 3 files changed, 48 insertions(+), 2 deletions(-) + create mode 100644 sysdeps/pthread/tst-pthread-exit-signal.c + +diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c +index bc213f0..3db0c9f 100644 +--- a/nptl/pthread_create.c ++++ b/nptl/pthread_create.c +@@ -407,8 +407,6 @@ start_thread (void *arg) + unwind_buf.priv.data.prev = NULL; + unwind_buf.priv.data.cleanup = NULL; + +- __libc_signal_restore_set (&pd->sigmask); +- + /* Allow setxid from now onwards. */ + if (__glibc_unlikely (atomic_exchange_acq (&pd->setxid_futex, 0) == -2)) + futex_wake (&pd->setxid_futex, 1, FUTEX_PRIVATE); +@@ -418,6 +416,8 @@ start_thread (void *arg) + /* Store the new cleanup handler info. */ + THREAD_SETMEM (pd, cleanup_jmp_buf, &unwind_buf); + ++ __libc_signal_restore_set (&pd->sigmask); ++ + LIBC_PROBE (pthread_start, 3, (pthread_t) pd, pd->start_routine, pd->arg); + + /* Run the code the user provided. */ +diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile +index df8943f..c657101 100644 +--- a/sysdeps/pthread/Makefile ++++ b/sysdeps/pthread/Makefile +@@ -118,6 +118,7 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ + tst-unload \ + tst-unwind-thread \ + tst-pt-vfork1 tst-pt-vfork2 tst-vfork1x tst-vfork2x \ ++ tst-pthread-exit-signal \ + tst-pthread-setuid-loop \ + tst-pthread_cancel-exited \ + tst-pthread_cancel-select-loop \ +diff --git a/sysdeps/pthread/tst-pthread-exit-signal.c b/sysdeps/pthread/tst-pthread-exit-signal.c +new file mode 100644 +index 0000000..b4526fe +--- /dev/null ++++ b/sysdeps/pthread/tst-pthread-exit-signal.c +@@ -0,0 +1,45 @@ ++/* Test that pending signals are not delivered on thread exit (bug 28607). ++ 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 ++ . */ ++ ++/* Due to bug 28607, pthread_kill (or pthread_cancel) restored the ++ signal mask during during thread exit, triggering the delivery of a ++ blocked pending signal (SIGUSR1 in this test). */ ++ ++#include ++#include ++ ++static void * ++threadfunc (void *closure) ++{ ++ sigset_t sigmask; ++ sigfillset (&sigmask); ++ xpthread_sigmask (SIG_SETMASK, &sigmask, NULL); ++ xpthread_kill (pthread_self (), SIGUSR1); ++ pthread_exit (NULL); ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ pthread_t thr = xpthread_create (NULL, threadfunc, NULL); ++ xpthread_join (thr); ++ return 0; ++} ++ ++#include +-- +1.8.3.1 + diff --git a/nptl-Fix-race-between-pthread_kill-and-thread-exit-b.patch b/nptl-Fix-race-between-pthread_kill-and-thread-exit-b.patch new file mode 100644 index 0000000000000000000000000000000000000000..3acbe2325cbb41db515f6a50648ef13d118acdaf --- /dev/null +++ b/nptl-Fix-race-between-pthread_kill-and-thread-exit-b.patch @@ -0,0 +1,424 @@ +From 526c3cf11ee9367344b6b15d669e4c3cb461a2be Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Mon, 13 Sep 2021 11:06:08 +0200 +Subject: [PATCH] nptl: Fix race between pthread_kill and thread exit (bug + 12889) + +A new thread exit lock and flag are introduced. They are used to +detect that the thread is about to exit or has exited in +__pthread_kill_internal, and the signal is not sent in this case. + +The test sysdeps/pthread/tst-pthread_cancel-select-loop.c is derived +from a downstream test originally written by Marek Polacek. + +Reviewed-by: Adhemerval Zanella +--- + nptl/allocatestack.c | 3 + + nptl/descr.h | 6 ++ + nptl/pthread_create.c | 14 +++ + nptl/pthread_kill.c | 65 +++++++----- + sysdeps/pthread/Makefile | 2 + + sysdeps/pthread/tst-pthread_cancel-select-loop.c | 87 ++++++++++++++++ + sysdeps/pthread/tst-pthread_kill-exiting.c | 123 +++++++++++++++++++++++ + 7 files changed, 275 insertions(+), 25 deletions(-) + create mode 100644 sysdeps/pthread/tst-pthread_cancel-select-loop.c + create mode 100644 sysdeps/pthread/tst-pthread_kill-exiting.c + +diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c +index 0356993..fa81007 100644 +--- a/nptl/allocatestack.c ++++ b/nptl/allocatestack.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + + /* Default alignment of stack. */ + #ifndef STACK_ALIGN +@@ -126,6 +127,8 @@ get_cached_stack (size_t *sizep, void **memp) + /* No pending event. */ + result->nextevent = NULL; + ++ result->exiting = false; ++ __libc_lock_init (result->exit_lock); + result->tls_state = (struct tls_internal_t) { 0 }; + + /* Clear the DTV. */ +diff --git a/nptl/descr.h b/nptl/descr.h +index e1c8831..41ee56f 100644 +--- a/nptl/descr.h ++++ b/nptl/descr.h +@@ -395,6 +395,12 @@ struct pthread + PTHREAD_CANCEL_ASYNCHRONOUS). */ + unsigned char canceltype; + ++ /* Used in __pthread_kill_internal to detected a thread that has ++ exited or is about to exit. exit_lock must only be acquired ++ after blocking signals. */ ++ bool exiting; ++ int exit_lock; /* A low-level lock (for use with __libc_lock_init etc). */ ++ + /* Used on strsignal. */ + struct tls_internal_t tls_state; + +diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c +index 7607f36..a559f86 100644 +--- a/nptl/pthread_create.c ++++ b/nptl/pthread_create.c +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + + #include + +@@ -484,6 +485,19 @@ start_thread (void *arg) + /* This was the last thread. */ + exit (0); + ++ /* This prevents sending a signal from this thread to itself during ++ its final stages. This must come after the exit call above ++ because atexit handlers must not run with signals blocked. */ ++ __libc_signal_block_all (NULL); ++ ++ /* Tell __pthread_kill_internal that this thread is about to exit. ++ If there is a __pthread_kill_internal in progress, this delays ++ the thread exit until the signal has been queued by the kernel ++ (so that the TID used to send it remains valid). */ ++ __libc_lock_lock (pd->exit_lock); ++ pd->exiting = true; ++ __libc_lock_unlock (pd->exit_lock); ++ + #ifndef __ASSUME_SET_ROBUST_LIST + /* If this thread has any robust mutexes locked, handle them now. */ + # if __PTHREAD_MUTEX_HAVE_PREV +diff --git a/nptl/pthread_kill.c b/nptl/pthread_kill.c +index 5d4c86f..fb7862e 100644 +--- a/nptl/pthread_kill.c ++++ b/nptl/pthread_kill.c +@@ -16,6 +16,7 @@ + License along with the GNU C Library; if not, see + . */ + ++#include + #include + #include + #include +@@ -23,37 +24,51 @@ + int + __pthread_kill_internal (pthread_t threadid, int signo) + { +- pid_t tid; + struct pthread *pd = (struct pthread *) threadid; +- + if (pd == THREAD_SELF) +- /* It is a special case to handle raise() implementation after a vfork +- call (which does not update the PD tid field). */ +- tid = INLINE_SYSCALL_CALL (gettid); +- else +- /* Force load of pd->tid into local variable or register. Otherwise +- if a thread exits between ESRCH test and tgkill, we might return +- EINVAL, because pd->tid would be cleared by the kernel. */ +- tid = atomic_forced_read (pd->tid); +- +- int val; +- if (__glibc_likely (tid > 0)) + { +- pid_t pid = __getpid (); +- +- val = INTERNAL_SYSCALL_CALL (tgkill, pid, tid, signo); +- val = (INTERNAL_SYSCALL_ERROR_P (val) +- ? INTERNAL_SYSCALL_ERRNO (val) : 0); ++ /* Use the actual TID from the kernel, so that it refers to the ++ current thread even if called after vfork. There is no ++ signal blocking in this case, so that the signal is delivered ++ immediately, before __pthread_kill_internal returns: a signal ++ sent to the thread itself needs to be delivered ++ synchronously. (It is unclear if Linux guarantees the ++ delivery of all pending signals after unblocking in the code ++ below. POSIX only guarantees delivery of a single signal, ++ which may not be the right one.) */ ++ pid_t tid = INTERNAL_SYSCALL_CALL (gettid); ++ int ret = INTERNAL_SYSCALL_CALL (kill, tid, signo); ++ return INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0; + } ++ ++ /* Block all signals, as required by pd->exit_lock. */ ++ sigset_t old_mask; ++ __libc_signal_block_all (&old_mask); ++ __libc_lock_lock (pd->exit_lock); ++ ++ int ret; ++ if (pd->exiting) ++ /* The thread is about to exit (or has exited). Sending the ++ signal is either not observable (the target thread has already ++ blocked signals at this point), or it will fail, or it might be ++ delivered to a new, unrelated thread that has reused the TID. ++ So do not actually send the signal. Do not report an error ++ because the threadid argument is still valid (the thread ID ++ lifetime has not ended), and ESRCH (for example) would be ++ misleading. */ ++ ret = 0; + else +- /* The kernel reports that the thread has exited. POSIX specifies +- the ESRCH error only for the case when the lifetime of a thread +- ID has ended, but calling pthread_kill on such a thread ID is +- undefined in glibc. Therefore, do not treat kernel thread exit +- as an error. */ +- val = 0; ++ { ++ /* Using tgkill is a safety measure. pd->exit_lock ensures that ++ the target thread cannot exit. */ ++ ret = INTERNAL_SYSCALL_CALL (tgkill, __getpid (), pd->tid, signo); ++ ret = INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0; ++ } ++ ++ __libc_lock_unlock (pd->exit_lock); ++ __libc_signal_restore_set (&old_mask); + +- return val; ++ return ret; + } + + int +diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile +index dedfa0d..48dba71 100644 +--- a/sysdeps/pthread/Makefile ++++ b/sysdeps/pthread/Makefile +@@ -119,7 +119,9 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ + tst-unwind-thread \ + tst-pt-vfork1 tst-pt-vfork2 tst-vfork1x tst-vfork2x \ + tst-pthread_cancel-exited \ ++ tst-pthread_cancel-select-loop \ + tst-pthread_kill-exited \ ++ tst-pthread_kill-exiting \ + # tests + + tests-time64 := \ +diff --git a/sysdeps/pthread/tst-pthread_cancel-select-loop.c b/sysdeps/pthread/tst-pthread_cancel-select-loop.c +new file mode 100644 +index 0000000..a620875 +--- /dev/null ++++ b/sysdeps/pthread/tst-pthread_cancel-select-loop.c +@@ -0,0 +1,87 @@ ++/* Test that pthread_cancel succeeds during thread exit. ++ 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 ++ . */ ++ ++/* This test tries to trigger an internal race condition in ++ pthread_cancel, where the cancellation signal is sent after the ++ thread has begun the cancellation process. This can result in a ++ spurious ESRCH error. For the original bug 12889, the window is ++ quite small, so the bug was not reproduced in every run. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Set to true by timeout_thread_function when the test should ++ terminate. */ ++static bool timeout; ++ ++static void * ++timeout_thread_function (void *unused) ++{ ++ usleep (5 * 1000 * 1000); ++ __atomic_store_n (&timeout, true, __ATOMIC_RELAXED); ++ return NULL; ++} ++ ++/* Used for blocking the select function below. */ ++static int pipe_fds[2]; ++ ++static void * ++canceled_thread_function (void *unused) ++{ ++ while (true) ++ { ++ fd_set rfs; ++ fd_set wfs; ++ fd_set efs; ++ FD_ZERO (&rfs); ++ FD_ZERO (&wfs); ++ FD_ZERO (&efs); ++ FD_SET (pipe_fds[0], &rfs); ++ ++ /* If the cancellation request is recognized early, the thread ++ begins exiting while the cancellation signal arrives. */ ++ select (FD_SETSIZE, &rfs, &wfs, &efs, NULL); ++ } ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ xpipe (pipe_fds); ++ pthread_t thr_timeout = xpthread_create (NULL, timeout_thread_function, NULL); ++ ++ while (!__atomic_load_n (&timeout, __ATOMIC_RELAXED)) ++ { ++ pthread_t thr = xpthread_create (NULL, canceled_thread_function, NULL); ++ xpthread_cancel (thr); ++ TEST_VERIFY (xpthread_join (thr) == PTHREAD_CANCELED); ++ } ++ ++ xpthread_join (thr_timeout); ++ xclose (pipe_fds[0]); ++ xclose (pipe_fds[1]); ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/pthread/tst-pthread_kill-exiting.c b/sysdeps/pthread/tst-pthread_kill-exiting.c +new file mode 100644 +index 0000000..f803e94 +--- /dev/null ++++ b/sysdeps/pthread/tst-pthread_kill-exiting.c +@@ -0,0 +1,123 @@ ++/* Test that pthread_kill succeeds during thread exit. ++ 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 ++ . */ ++ ++/* This test verifies that pthread_kill for a thread that is exiting ++ succeeds (with or without actually delivering the signal). */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Set to true by timeout_thread_function when the test should ++ terminate. */ ++static bool timeout; ++ ++static void * ++timeout_thread_function (void *unused) ++{ ++ usleep (1000 * 1000); ++ __atomic_store_n (&timeout, true, __ATOMIC_RELAXED); ++ return NULL; ++} ++ ++/* Used to synchronize the sending threads with the target thread and ++ main thread. */ ++static pthread_barrier_t barrier_1; ++static pthread_barrier_t barrier_2; ++ ++/* The target thread to which signals are to be sent. */ ++static pthread_t target_thread; ++ ++/* Set by the main thread to true after timeout has been set to ++ true. */ ++static bool exiting; ++ ++static void * ++sender_thread_function (void *unused) ++{ ++ while (true) ++ { ++ /* Wait until target_thread has been initialized. The target ++ thread and main thread participate in this barrier. */ ++ xpthread_barrier_wait (&barrier_1); ++ ++ if (exiting) ++ break; ++ ++ xpthread_kill (target_thread, SIGUSR1); ++ ++ /* Communicate that the signal has been sent. The main thread ++ participates in this barrier. */ ++ xpthread_barrier_wait (&barrier_2); ++ } ++ return NULL; ++} ++ ++static void * ++target_thread_function (void *unused) ++{ ++ target_thread = pthread_self (); ++ xpthread_barrier_wait (&barrier_1); ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ xsignal (SIGUSR1, SIG_IGN); ++ ++ pthread_t thr_timeout = xpthread_create (NULL, timeout_thread_function, NULL); ++ ++ pthread_t threads[4]; ++ xpthread_barrier_init (&barrier_1, NULL, array_length (threads) + 2); ++ xpthread_barrier_init (&barrier_2, NULL, array_length (threads) + 1); ++ ++ for (int i = 0; i < array_length (threads); ++i) ++ threads[i] = xpthread_create (NULL, sender_thread_function, NULL); ++ ++ while (!__atomic_load_n (&timeout, __ATOMIC_RELAXED)) ++ { ++ xpthread_create (NULL, target_thread_function, NULL); ++ ++ /* Wait for the target thread to be set up and signal sending to ++ start. */ ++ xpthread_barrier_wait (&barrier_1); ++ ++ /* Wait for signal sending to complete. */ ++ xpthread_barrier_wait (&barrier_2); ++ ++ xpthread_join (target_thread); ++ } ++ ++ exiting = true; ++ ++ /* Signal the sending threads to exit. */ ++ xpthread_create (NULL, target_thread_function, NULL); ++ xpthread_barrier_wait (&barrier_1); ++ ++ for (int i = 0; i < array_length (threads); ++i) ++ xpthread_join (threads[i]); ++ xpthread_join (thr_timeout); ++ ++ return 0; ++} ++ ++#include +-- +1.8.3.1 + diff --git a/nptl-Fix-type-of-pthread_mutexattr_getrobust_np-pthr.patch b/nptl-Fix-type-of-pthread_mutexattr_getrobust_np-pthr.patch new file mode 100644 index 0000000000000000000000000000000000000000..b92e3c5ac066bdafbd925fb7da27dbc8138f8c79 --- /dev/null +++ b/nptl-Fix-type-of-pthread_mutexattr_getrobust_np-pthr.patch @@ -0,0 +1,37 @@ +From f3e664563361dc17530113b3205998d1f19dc4d9 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Tue, 21 Sep 2021 07:12:56 +0200 +Subject: [PATCH] nptl: Fix type of pthread_mutexattr_getrobust_np, + pthread_mutexattr_setrobust_np (bug 28036) + +Reviewed-by: Carlos O'Donell +Tested-by: Carlos O'Donell +--- + sysdeps/nptl/pthread.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h +index f1b7f2b..43146e9 100644 +--- a/sysdeps/nptl/pthread.h ++++ b/sysdeps/nptl/pthread.h +@@ -933,7 +933,7 @@ extern int pthread_mutexattr_getrobust (const pthread_mutexattr_t *__attr, + # ifdef __USE_GNU + # ifdef __REDIRECT_NTH + extern int __REDIRECT_NTH (pthread_mutexattr_getrobust_np, +- (pthread_mutex_t *, int *), ++ (pthread_mutexattr_t *, int *), + pthread_mutexattr_getrobust) __nonnull ((1)) + __attribute_deprecated_msg__ ("\ + pthread_mutexattr_getrobust_np is deprecated, use pthread_mutexattr_getrobust"); +@@ -949,7 +949,7 @@ extern int pthread_mutexattr_setrobust (pthread_mutexattr_t *__attr, + # ifdef __USE_GNU + # ifdef __REDIRECT_NTH + extern int __REDIRECT_NTH (pthread_mutexattr_setrobust_np, +- (pthread_mutex_t *, int), ++ (pthread_mutexattr_t *, int), + pthread_mutexattr_setrobust) __nonnull ((1)) + __attribute_deprecated_msg__ ("\ + pthread_mutexattr_setrobust_np is deprecated, use pthread_mutexattr_setrobust"); +-- +1.8.3.1 + diff --git a/nptl-pthread_kill-must-send-signals-to-a-specific-th.patch b/nptl-pthread_kill-must-send-signals-to-a-specific-th.patch new file mode 100644 index 0000000000000000000000000000000000000000..87683c361626d662a809dea2215bbd596b18012a --- /dev/null +++ b/nptl-pthread_kill-must-send-signals-to-a-specific-th.patch @@ -0,0 +1,162 @@ +From eae81d70574e923ce3c59078b8df857ae192efa6 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 1 Oct 2021 18:16:41 +0200 +Subject: [PATCH] nptl: pthread_kill must send signals to a specific thread [BZ + #28407] + +The choice between the kill vs tgkill system calls is not just about +the TID reuse race, but also about whether the signal is sent to the +whole process (and any thread in it) or to a specific thread. + +This was caught by the openposix test suite: + + LTP: openposix test suite - FAIL: SIGUSR1 is member of new thread pendingset. + + +Fixes commit 526c3cf11ee9367344b6b15d669e4c3cb461a2be ("nptl: Fix race +between pthread_kill and thread exit (bug 12889)"). + +Reviewed-by: Carlos O'Donell +Tested-by: Carlos O'Donell +--- + nptl/pthread_kill.c | 4 +- + sysdeps/pthread/Makefile | 1 + + sysdeps/pthread/tst-pthread-raise-blocked-self.c | 92 ++++++++++++++++++++++++ + 3 files changed, 94 insertions(+), 3 deletions(-) + create mode 100644 sysdeps/pthread/tst-pthread-raise-blocked-self.c + +diff --git a/nptl/pthread_kill.c b/nptl/pthread_kill.c +index a44dc8f..35bf1f9 100644 +--- a/nptl/pthread_kill.c ++++ b/nptl/pthread_kill.c +@@ -40,7 +40,7 @@ __pthread_kill_implementation (pthread_t threadid, int signo, int no_tid) + below. POSIX only guarantees delivery of a single signal, + which may not be the right one.) */ + pid_t tid = INTERNAL_SYSCALL_CALL (gettid); +- int ret = INTERNAL_SYSCALL_CALL (kill, tid, signo); ++ int ret = INTERNAL_SYSCALL_CALL (tgkill, __getpid (), tid, signo); + return INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0; + } + +@@ -59,8 +59,6 @@ __pthread_kill_implementation (pthread_t threadid, int signo, int no_tid) + ret = no_tid; + else + { +- /* Using tgkill is a safety measure. pd->exit_lock ensures that +- the target thread cannot exit. */ + ret = INTERNAL_SYSCALL_CALL (tgkill, __getpid (), pd->tid, signo); + ret = INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0; + } +diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile +index d4bd2d4..0af9c59 100644 +--- a/sysdeps/pthread/Makefile ++++ b/sysdeps/pthread/Makefile +@@ -121,6 +121,7 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ + tst-pthread-setuid-loop \ + tst-pthread_cancel-exited \ + tst-pthread_cancel-select-loop \ ++ tst-pthread-raise-blocked-self \ + tst-pthread_kill-exited \ + tst-pthread_kill-exiting \ + # tests +diff --git a/sysdeps/pthread/tst-pthread-raise-blocked-self.c b/sysdeps/pthread/tst-pthread-raise-blocked-self.c +new file mode 100644 +index 0000000..128e1a6 +--- /dev/null ++++ b/sysdeps/pthread/tst-pthread-raise-blocked-self.c +@@ -0,0 +1,92 @@ ++/* Test that raise sends signal to current thread even if blocked. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Used to create a dummy thread ID distinct from all other thread ++ IDs. */ ++static void * ++noop (void *ignored) ++{ ++ return NULL; ++} ++ ++static volatile pthread_t signal_thread; ++ ++static void ++signal_handler (int signo) ++{ ++ signal_thread = pthread_self (); ++} ++ ++/* Used to ensure that waiting_thread has launched and can accept ++ signals. */ ++static pthread_barrier_t barrier; ++ ++static void * ++waiting_thread (void *ignored) ++{ ++ xpthread_barrier_wait (&barrier); ++ pause (); ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ xsignal (SIGUSR1, signal_handler); ++ xpthread_barrier_init (&barrier, NULL, 2); ++ ++ /* Distinct thread ID value to */ ++ pthread_t dummy = xpthread_create (NULL, noop, NULL); ++ signal_thread = dummy; ++ ++ pthread_t helper = xpthread_create (NULL, waiting_thread, NULL); ++ ++ /* Make sure that the thread is running. */ ++ xpthread_barrier_wait (&barrier); ++ ++ /* Block signals on this thread. */ ++ sigset_t set; ++ sigfillset (&set); ++ xpthread_sigmask (SIG_BLOCK, &set, NULL); ++ ++ /* Send the signal to this thread. It must not be delivered. */ ++ raise (SIGUSR1); ++ TEST_VERIFY (signal_thread == dummy); ++ ++ /* Wait a bit to give a chance for signal delivery (increases ++ chances of failure with bug 28407). */ ++ usleep (50 * 1000); ++ ++ /* Unblocking should cause synchronous delivery of the signal. */ ++ xpthread_sigmask (SIG_UNBLOCK, &set, NULL); ++ TEST_VERIFY (signal_thread == pthread_self ()); ++ ++ xpthread_cancel (helper); ++ xpthread_join (helper); ++ xpthread_join (dummy); ++ return 0; ++} ++ ++#include +-- +1.8.3.1 + diff --git a/nptl-pthread_kill-needs-to-return-ESRCH-for-old-prog.patch b/nptl-pthread_kill-needs-to-return-ESRCH-for-old-prog.patch new file mode 100644 index 0000000000000000000000000000000000000000..d52abb8c51e80541d5ba7f96317ada368aa0c39d --- /dev/null +++ b/nptl-pthread_kill-needs-to-return-ESRCH-for-old-prog.patch @@ -0,0 +1,142 @@ +From 95dba35bf05e4a5d69dfae5e9c9d4df3646a7f93 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Mon, 20 Sep 2021 14:56:08 +0200 +Subject: [PATCH] nptl: pthread_kill needs to return ESRCH for old programs + (bug 19193) + +The fix for bug 19193 breaks some old applications which appear +to use pthread_kill to probe if a thread is still running, something +that is not supported by POSIX. +--- + nptl/pthread_kill.c | 37 ++++++++++++++++++++++++------- + sysdeps/pthread/tst-pthread_kill-exited.c | 21 ++++++++++++++++-- + 2 files changed, 48 insertions(+), 10 deletions(-) + +diff --git a/nptl/pthread_kill.c b/nptl/pthread_kill.c +index fb7862e..a44dc8f 100644 +--- a/nptl/pthread_kill.c ++++ b/nptl/pthread_kill.c +@@ -21,8 +21,11 @@ + #include + #include + +-int +-__pthread_kill_internal (pthread_t threadid, int signo) ++/* Sends SIGNO to THREADID. If the thread is about to exit or has ++ already exited on the kernel side, return NO_TID. Otherwise return ++ 0 or an error code. */ ++static int ++__pthread_kill_implementation (pthread_t threadid, int signo, int no_tid) + { + struct pthread *pd = (struct pthread *) threadid; + if (pd == THREAD_SELF) +@@ -52,11 +55,8 @@ __pthread_kill_internal (pthread_t threadid, int signo) + signal is either not observable (the target thread has already + blocked signals at this point), or it will fail, or it might be + delivered to a new, unrelated thread that has reused the TID. +- So do not actually send the signal. Do not report an error +- because the threadid argument is still valid (the thread ID +- lifetime has not ended), and ESRCH (for example) would be +- misleading. */ +- ret = 0; ++ So do not actually send the signal. */ ++ ret = no_tid; + else + { + /* Using tgkill is a safety measure. pd->exit_lock ensures that +@@ -72,6 +72,15 @@ __pthread_kill_internal (pthread_t threadid, int signo) + } + + int ++__pthread_kill_internal (pthread_t threadid, int signo) ++{ ++ /* Do not report an error in the no-tid case because the threadid ++ argument is still valid (the thread ID lifetime has not ended), ++ and ESRCH (for example) would be misleading. */ ++ return __pthread_kill_implementation (threadid, signo, 0); ++} ++ ++int + __pthread_kill (pthread_t threadid, int signo) + { + /* Disallow sending the signal we use for cancellation, timers, +@@ -81,6 +90,7 @@ __pthread_kill (pthread_t threadid, int signo) + + return __pthread_kill_internal (threadid, signo); + } ++ + /* Some architectures (for instance arm) might pull raise through libgcc, so + avoid the symbol version if it ends up being used on ld.so. */ + #if !IS_IN(rtld) +@@ -88,6 +98,17 @@ libc_hidden_def (__pthread_kill) + versioned_symbol (libc, __pthread_kill, pthread_kill, GLIBC_2_34); + + # if OTHER_SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34) +-compat_symbol (libc, __pthread_kill, pthread_kill, GLIBC_2_0); ++/* Variant which returns ESRCH in the no-TID case, for backwards ++ compatibility. */ ++int ++attribute_compat_text_section ++__pthread_kill_esrch (pthread_t threadid, int signo) ++{ ++ if (__is_internal_signal (signo)) ++ return EINVAL; ++ ++ return __pthread_kill_implementation (threadid, signo, ESRCH); ++} ++compat_symbol (libc, __pthread_kill_esrch, pthread_kill, GLIBC_2_0); + # endif + #endif +diff --git a/sysdeps/pthread/tst-pthread_kill-exited.c b/sysdeps/pthread/tst-pthread_kill-exited.c +index 7575fb6..a2fddad 100644 +--- a/sysdeps/pthread/tst-pthread_kill-exited.c ++++ b/sysdeps/pthread/tst-pthread_kill-exited.c +@@ -16,11 +16,15 @@ + License along with the GNU C Library; if not, see + . */ + +-/* This test verifies that pthread_kill returns 0 (and not ESRCH) for +- a thread that has exited on the kernel side. */ ++/* This test verifies that the default pthread_kill returns 0 (and not ++ ESRCH) for a thread that has exited on the kernel side. */ + ++#include ++#include ++#include + #include + #include ++#include + #include + #include + +@@ -30,6 +34,12 @@ noop_thread (void *closure) + return NULL; + } + ++#if TEST_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34) && PTHREAD_IN_LIBC ++extern __typeof (pthread_kill) compat_pthread_kill; ++compat_symbol_reference (libpthread, compat_pthread_kill, pthread_kill, ++ GLIBC_2_0); ++#endif ++ + static int + do_test (void) + { +@@ -37,7 +47,14 @@ do_test (void) + + support_wait_for_thread_exit (); + ++ /* NB: Always uses the default symbol due to separate compilation. */ + xpthread_kill (thr, SIGUSR1); ++ ++#if TEST_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34) && PTHREAD_IN_LIBC ++ /* Old binaries need the non-conforming ESRCH error code. */ ++ TEST_COMPARE (compat_pthread_kill (thr, SIGUSR1), ESRCH); ++#endif ++ + xpthread_join (thr); + + return 0; +-- +1.8.3.1 + diff --git a/nptl-pthread_kill-pthread_cancel-should-not-fail-aft.patch b/nptl-pthread_kill-pthread_cancel-should-not-fail-aft.patch new file mode 100644 index 0000000000000000000000000000000000000000..7d1bc81fe6a21a03129f997e05df7eba32bba728 --- /dev/null +++ b/nptl-pthread_kill-pthread_cancel-should-not-fail-aft.patch @@ -0,0 +1,292 @@ +From 8af8456004edbab71f8903a60a3cae442cf6fe69 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Mon, 13 Sep 2021 11:06:08 +0200 +Subject: [PATCH] nptl: pthread_kill, pthread_cancel should not fail after exit + (bug 19193) + +This closes one remaining race condition related to bug 12889: if +the thread already exited on the kernel side, returning ESRCH +is not correct because that error is reserved for the thread IDs +(pthread_t values) whose lifetime has ended. In case of a +kernel-side exit and a valid thread ID, no signal needs to be sent +and cancellation does not have an effect, so just return 0. + +sysdeps/pthread/tst-kill4.c triggers undefined behavior and is +removed with this commit. + +Reviewed-by: Adhemerval Zanella +--- + nptl/pthread_cancel.c | 9 +-- + nptl/pthread_kill.c | 7 ++- + sysdeps/pthread/Makefile | 5 +- + sysdeps/pthread/tst-kill4.c | 90 ----------------------------- + sysdeps/pthread/tst-pthread_cancel-exited.c | 45 +++++++++++++++ + sysdeps/pthread/tst-pthread_kill-exited.c | 46 +++++++++++++++ + 6 files changed, 106 insertions(+), 96 deletions(-) + delete mode 100644 sysdeps/pthread/tst-kill4.c + create mode 100644 sysdeps/pthread/tst-pthread_cancel-exited.c + create mode 100644 sysdeps/pthread/tst-pthread_kill-exited.c + +diff --git a/nptl/pthread_cancel.c b/nptl/pthread_cancel.c +index 2bb523c..a8aa3b3 100644 +--- a/nptl/pthread_cancel.c ++++ b/nptl/pthread_cancel.c +@@ -61,10 +61,11 @@ __pthread_cancel (pthread_t th) + { + volatile struct pthread *pd = (volatile struct pthread *) th; + +- /* Make sure the descriptor is valid. */ +- if (INVALID_TD_P (pd)) +- /* Not a valid thread handle. */ +- return ESRCH; ++ if (pd->tid == 0) ++ /* The thread has already exited on the kernel side. Its outcome ++ (regular exit, other cancelation) has already been ++ determined. */ ++ return 0; + + static int init_sigcancel = 0; + if (atomic_load_relaxed (&init_sigcancel) == 0) +diff --git a/nptl/pthread_kill.c b/nptl/pthread_kill.c +index f79a2b2..5d4c86f 100644 +--- a/nptl/pthread_kill.c ++++ b/nptl/pthread_kill.c +@@ -46,7 +46,12 @@ __pthread_kill_internal (pthread_t threadid, int signo) + ? INTERNAL_SYSCALL_ERRNO (val) : 0); + } + else +- val = ESRCH; ++ /* The kernel reports that the thread has exited. POSIX specifies ++ the ESRCH error only for the case when the lifetime of a thread ++ ID has ended, but calling pthread_kill on such a thread ID is ++ undefined in glibc. Therefore, do not treat kernel thread exit ++ as an error. */ ++ val = 0; + + return val; + } +diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile +index 42f9fc5..dedfa0d 100644 +--- a/sysdeps/pthread/Makefile ++++ b/sysdeps/pthread/Makefile +@@ -89,7 +89,7 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ + tst-join8 tst-join9 tst-join10 tst-join11 tst-join12 tst-join13 \ + tst-join14 tst-join15 \ + tst-key1 tst-key2 tst-key3 tst-key4 \ +- tst-kill1 tst-kill2 tst-kill3 tst-kill4 tst-kill5 tst-kill6 \ ++ tst-kill1 tst-kill2 tst-kill3 tst-kill5 tst-kill6 \ + tst-locale1 tst-locale2 \ + tst-memstream \ + tst-mutex-errorcheck tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 \ +@@ -118,6 +118,9 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ + tst-unload \ + tst-unwind-thread \ + tst-pt-vfork1 tst-pt-vfork2 tst-vfork1x tst-vfork2x \ ++ tst-pthread_cancel-exited \ ++ tst-pthread_kill-exited \ ++ # tests + + tests-time64 := \ + tst-abstime-time64 \ +diff --git a/sysdeps/pthread/tst-kill4.c b/sysdeps/pthread/tst-kill4.c +deleted file mode 100644 +index 222ceb7..0000000 +--- a/sysdeps/pthread/tst-kill4.c ++++ /dev/null +@@ -1,90 +0,0 @@ +-/* Copyright (C) 2003-2021 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- Contributed by Ulrich Drepper , 2003. +- +- 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 +- . */ +- +-#include +-#include +-#include +-#include +-#include +-#include +- +- +-static void * +-tf (void *a) +-{ +- return NULL; +-} +- +- +-int +-do_test (void) +-{ +- pthread_attr_t at; +- if (pthread_attr_init (&at) != 0) +- { +- puts ("attr_create failed"); +- exit (1); +- } +- +- /* Limit thread stack size, because if it is too large, pthread_join +- will free it immediately rather than put it into stack cache. */ +- if (pthread_attr_setstacksize (&at, 2 * 1024 * 1024) != 0) +- { +- puts ("setstacksize failed"); +- exit (1); +- } +- +- pthread_t th; +- if (pthread_create (&th, &at, tf, NULL) != 0) +- { +- puts ("create failed"); +- exit (1); +- } +- +- pthread_attr_destroy (&at); +- +- if (pthread_join (th, NULL) != 0) +- { +- puts ("join failed"); +- exit (1); +- } +- +- /* The following only works because we assume here something about +- the implementation. Namely, that the memory allocated for the +- thread descriptor is not going away, that the TID field is +- cleared and therefore the signal is sent to process 0, and that +- we can savely assume there is no other process with this ID at +- that time. */ +- int e = pthread_kill (th, 0); +- if (e == 0) +- { +- puts ("pthread_kill succeeded"); +- exit (1); +- } +- if (e != ESRCH) +- { +- puts ("pthread_kill didn't return ESRCH"); +- exit (1); +- } +- +- return 0; +-} +- +- +-#define TEST_FUNCTION do_test () +-#include "../test-skeleton.c" +diff --git a/sysdeps/pthread/tst-pthread_cancel-exited.c b/sysdeps/pthread/tst-pthread_cancel-exited.c +new file mode 100644 +index 0000000..811c9be +--- /dev/null ++++ b/sysdeps/pthread/tst-pthread_cancel-exited.c +@@ -0,0 +1,45 @@ ++/* Test that pthread_kill succeeds for an exited thread. ++ 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 ++ . */ ++ ++/* This test verifies that pthread_kill returns 0 (and not ESRCH) for ++ a thread that has exited on the kernel side. */ ++ ++#include ++#include ++#include ++ ++static void * ++noop_thread (void *closure) ++{ ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ pthread_t thr = xpthread_create (NULL, noop_thread, NULL); ++ ++ support_wait_for_thread_exit (); ++ ++ xpthread_cancel (thr); ++ xpthread_join (thr); ++ ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/pthread/tst-pthread_kill-exited.c b/sysdeps/pthread/tst-pthread_kill-exited.c +new file mode 100644 +index 0000000..7575fb6 +--- /dev/null ++++ b/sysdeps/pthread/tst-pthread_kill-exited.c +@@ -0,0 +1,46 @@ ++/* Test that pthread_kill succeeds for an exited thread. ++ 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 ++ . */ ++ ++/* This test verifies that pthread_kill returns 0 (and not ESRCH) for ++ a thread that has exited on the kernel side. */ ++ ++#include ++#include ++#include ++#include ++ ++static void * ++noop_thread (void *closure) ++{ ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ pthread_t thr = xpthread_create (NULL, noop_thread, NULL); ++ ++ support_wait_for_thread_exit (); ++ ++ xpthread_kill (thr, SIGUSR1); ++ xpthread_join (thr); ++ ++ return 0; ++} ++ ++#include +-- +1.8.3.1 + diff --git a/nscd.conf b/nscd.conf deleted file mode 100644 index 8a24a785e3093f0500f03f023092beefb527398f..0000000000000000000000000000000000000000 --- a/nscd.conf +++ /dev/null @@ -1 +0,0 @@ -d /run/nscd 0755 root root diff --git a/nss-Use-files-dns-as-the-default-for-the-hosts-datab.patch b/nss-Use-files-dns-as-the-default-for-the-hosts-datab.patch new file mode 100644 index 0000000000000000000000000000000000000000..28ff8601e5f2e1bd757a62a14d1d1bf18712b084 --- /dev/null +++ b/nss-Use-files-dns-as-the-default-for-the-hosts-datab.patch @@ -0,0 +1,81 @@ +From b99b0f93ee8762fe53ff65802deb6f00700b9924 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 17 Dec 2021 12:01:20 +0100 +Subject: [PATCH] nss: Use "files dns" as the default for the hosts database + (bug 28700) + +This matches what is currently in nss/nsswitch.conf. The new ordering +matches what most distributions use in their installed configuration +files. + +It is common to add localhost to /etc/hosts because the name does not +exist in the DNS, but is commonly used as a host name. + +With the built-in "dns [!UNAVAIL=return] files" default, dns is +searched first and provides an answer for "localhost" (NXDOMAIN). +We never look at the files database as a result, so the contents of +/etc/hosts is ignored. This means that "getent hosts localhost" +fail without a /etc/nsswitch.conf file, even though the host name +is listed in /etc/hosts. + +Reviewed-by: Carlos O'Donell +--- + manual/nss.texi | 5 ++--- + nss/XXX-lookup.c | 2 +- + nss/nss_database.c | 4 ++-- + 3 files changed, 5 insertions(+), 6 deletions(-) + +diff --git a/manual/nss.texi b/manual/nss.texi +index 3aaa778..524d22a 100644 +--- a/manual/nss.texi ++++ b/manual/nss.texi +@@ -324,9 +324,8 @@ missing. + + @cindex default value, and NSS + For the @code{hosts} and @code{networks} databases the default value is +-@code{dns [!UNAVAIL=return] files}. I.e., the system is prepared for +-the DNS service not to be available but if it is available the answer it +-returns is definitive. ++@code{files dns}. I.e., local configuration will override the contents ++of the domain name system (DNS). + + The @code{passwd}, @code{group}, and @code{shadow} databases was + traditionally handled in a special way. The appropriate files in the +diff --git a/nss/XXX-lookup.c b/nss/XXX-lookup.c +index 302c636..e129f69 100644 +--- a/nss/XXX-lookup.c ++++ b/nss/XXX-lookup.c +@@ -28,7 +28,7 @@ + |* ALTERNATE_NAME - name of another service which is examined in *| + |* case DATABASE_NAME is not found *| + |* *| +-|* DEFAULT_CONFIG - string for default conf (e.g. "dns files") *| ++|* DEFAULT_CONFIG - string for default conf (e.g. "files dns") *| + |* *| + \*******************************************************************/ + +diff --git a/nss/nss_database.c b/nss/nss_database.c +index ab121cb..54561f0 100644 +--- a/nss/nss_database.c ++++ b/nss/nss_database.c +@@ -80,7 +80,7 @@ enum nss_database_default + { + nss_database_default_defconfig = 0, /* "nis [NOTFOUND=return] files". */ + nss_database_default_compat, /* "compat [NOTFOUND=return] files". */ +- nss_database_default_dns, /* "dns [!UNAVAIL=return] files". */ ++ nss_database_default_dns, /* "files dns". */ + nss_database_default_files, /* "files". */ + nss_database_default_nis, /* "nis". */ + nss_database_default_nis_nisplus, /* "nis nisplus". */ +@@ -133,7 +133,7 @@ nss_database_select_default (struct nss_database_default_cache *cache, + #endif + + case nss_database_default_dns: +- line = "dns [!UNAVAIL=return] files"; ++ line = "files dns"; + break; + + case nss_database_default_files: +-- +1.8.3.1 + diff --git a/posix-Fix-attribute-access-mode-on-getcwd-BZ-27476.patch b/posix-Fix-attribute-access-mode-on-getcwd-BZ-27476.patch new file mode 100644 index 0000000000000000000000000000000000000000..a9e8d26b9e20df41fd1c5b911c4a99ef4db0dde4 --- /dev/null +++ b/posix-Fix-attribute-access-mode-on-getcwd-BZ-27476.patch @@ -0,0 +1,50 @@ +From 433ec4f14a5753c7689c83c20c9972915c53c204 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Fri, 10 Sep 2021 19:39:35 +0200 +Subject: [PATCH] posix: Fix attribute access mode on getcwd [BZ #27476] + +There is a GNU extension that allows to call getcwd(NULL, >0). It is +described in the documentation, but also directly in the unistd.h +header, just above the declaration. + +Therefore the attribute access mode added in commit 06febd8c6705 +is not correct. Drop it. +--- + posix/bits/unistd.h | 5 ++--- + posix/unistd.h | 3 +-- + 2 files changed, 3 insertions(+), 5 deletions(-) + +diff --git a/posix/bits/unistd.h b/posix/bits/unistd.h +index f083138..622adeb 100644 +--- a/posix/bits/unistd.h ++++ b/posix/bits/unistd.h +@@ -199,10 +199,9 @@ __NTH (readlinkat (int __fd, const char *__restrict __path, + #endif + + extern char *__getcwd_chk (char *__buf, size_t __size, size_t __buflen) +- __THROW __wur __attr_access ((__write_only__, 1, 2)); ++ __THROW __wur; + extern char *__REDIRECT_NTH (__getcwd_alias, +- (char *__buf, size_t __size), getcwd) +- __wur __attr_access ((__write_only__, 1, 2)); ++ (char *__buf, size_t __size), getcwd) __wur; + extern char *__REDIRECT_NTH (__getcwd_chk_warn, + (char *__buf, size_t __size, size_t __buflen), + __getcwd_chk) +diff --git a/posix/unistd.h b/posix/unistd.h +index 3dca657..8224c5f 100644 +--- a/posix/unistd.h ++++ b/posix/unistd.h +@@ -528,8 +528,7 @@ extern int fchdir (int __fd) __THROW __wur; + an array is allocated with `malloc'; the array is SIZE + bytes long, unless SIZE == 0, in which case it is as + big as necessary. */ +-extern char *getcwd (char *__buf, size_t __size) __THROW __wur +- __attr_access ((__write_only__, 1, 2)); ++extern char *getcwd (char *__buf, size_t __size) __THROW __wur; + + #ifdef __USE_GNU + /* Return a malloc'd string containing the current directory name. +-- +1.8.3.1 + diff --git a/pthread-tst-cancel28-Fix-barrier-re-init-race-condit.patch b/pthread-tst-cancel28-Fix-barrier-re-init-race-condit.patch new file mode 100644 index 0000000000000000000000000000000000000000..208821236906cd5b9a03ae1ade5a2f6888924cdb --- /dev/null +++ b/pthread-tst-cancel28-Fix-barrier-re-init-race-condit.patch @@ -0,0 +1,41 @@ +From 9874ca536b1d0662b1cea46af3ce09a4d42aeb32 Mon Sep 17 00:00:00 2001 +From: Stafford Horne +Date: Sat, 25 Sep 2021 17:02:06 +0900 +Subject: [PATCH] pthread/tst-cancel28: Fix barrier re-init race condition + +When running this test on the OpenRISC port I am working on this test +fails with a timeout. The test passes when being straced or debugged. +Looking at the code there seems to be a race condition in that: + + 1 main thread: calls xpthread_cancel + 2 sub thread : receives cancel signal + 3 sub thread : cleanup routine waits on barrier + 4 main thread: re-inits barrier + 5 main thread: waits on barrier + +After getting to 5 the main thread and sub thread wait forever as the 2 +barriers are no longer the same. + +Removing the barrier re-init seems to fix this issue. Also, the barrier +does not need to be reinitialized as that is done by default. + +Reviewed-by: Adhemerval Zanella +--- + sysdeps/pthread/tst-cancel28.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/sysdeps/pthread/tst-cancel28.c b/sysdeps/pthread/tst-cancel28.c +index 627cbc8..9286c15 100644 +--- a/sysdeps/pthread/tst-cancel28.c ++++ b/sysdeps/pthread/tst-cancel28.c +@@ -69,7 +69,6 @@ do_test (void) + + xpthread_cancel (timer_thread); + +- xpthread_barrier_init (&barrier, NULL, 2); + xpthread_barrier_wait (&barrier); + + return 0; +-- +1.8.3.1 + diff --git a/realpath-Set-errno-to-ENAMETOOLONG-for-result-larger.patch b/realpath-Set-errno-to-ENAMETOOLONG-for-result-larger.patch new file mode 100644 index 0000000000000000000000000000000000000000..c802dd92459043d5317572bba999c141e3c605da --- /dev/null +++ b/realpath-Set-errno-to-ENAMETOOLONG-for-result-larger.patch @@ -0,0 +1,138 @@ +From f7a79879c0b2bef0dadd6caaaeeb0d26423e04e5 Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +Date: Thu, 13 Jan 2022 11:28:36 +0530 +Subject: [PATCH] realpath: Set errno to ENAMETOOLONG for result larger than + PATH_MAX [BZ #28770] + +realpath returns an allocated string when the result exceeds PATH_MAX, +which is unexpected when its second argument is not NULL. This results +in the second argument (resolved) being uninitialized and also results +in a memory leak since the caller expects resolved to be the same as the +returned value. + +Return NULL and set errno to ENAMETOOLONG if the result exceeds +PATH_MAX. This fixes [BZ #28770], which is CVE-2021-3998. + +Reviewed-by: Adhemerval Zanella +Signed-off-by: Siddhesh Poyarekar +(cherry picked from commit ee8d5e33adb284601c00c94687bc907e10aec9bb) +--- + NEWS | 6 +++++ + stdlib/Makefile | 1 + + stdlib/canonicalize.c | 12 +++++++++-- + stdlib/tst-realpath-toolong.c | 49 +++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 65 insertions(+), 2 deletions(-) + create mode 100644 stdlib/tst-realpath-toolong.c + +diff --git a/NEWS b/NEWS +index 711420cb..db50b2af 100644 +--- a/NEWS ++++ b/NEWS +@@ -17,8 +17,14 @@ Security related changes: + CVE-2022-23218: Passing an overlong file name to the svcunix_create + legacy function could result in a stack-based buffer overflow. + ++ CVE-2021-3998: Passing a path longer than PATH_MAX to the realpath ++ function could result in a memory leak and potential access of ++ uninitialized memory. Reported by Qualys. ++ + The following bugs are resolved with this release: + ++ [12889] nptl: Fix race between pthread_kill and thread exit ++ [19193] nptl: pthread_kill, pthread_cancel should not fail after exit + [22542] CVE-2022-23219: Buffer overflow in sunrpc clnt_create for "unix" + + +diff --git a/stdlib/Makefile b/stdlib/Makefile +index 9bb5c221..a4ac30d1 100644 +--- a/stdlib/Makefile ++++ b/stdlib/Makefile +@@ -109,6 +109,7 @@ tests := \ + tst-random \ + tst-random2 \ + tst-realpath \ ++ tst-realpath-toolong \ + tst-secure-getenv \ + tst-setcontext \ + tst-setcontext2 \ +diff --git a/stdlib/canonicalize.c b/stdlib/canonicalize.c +index 698f9ede..7a23a51b 100644 +--- a/stdlib/canonicalize.c ++++ b/stdlib/canonicalize.c +@@ -400,8 +400,16 @@ realpath_stk (const char *name, char *resolved, + + error: + *dest++ = '\0'; +- if (resolved != NULL && dest - rname <= get_path_max ()) +- rname = strcpy (resolved, rname); ++ if (resolved != NULL) ++ { ++ if (dest - rname <= get_path_max ()) ++ rname = strcpy (resolved, rname); ++ else ++ { ++ failed = true; ++ __set_errno (ENAMETOOLONG); ++ } ++ } + + error_nomem: + scratch_buffer_free (&extra_buffer); +diff --git a/stdlib/tst-realpath-toolong.c b/stdlib/tst-realpath-toolong.c +new file mode 100644 +index 00000000..8bed7724 +--- /dev/null ++++ b/stdlib/tst-realpath-toolong.c +@@ -0,0 +1,49 @@ ++/* Verify that realpath returns NULL with ENAMETOOLONG if the result exceeds ++ NAME_MAX. ++ Copyright The GNU Toolchain Authors. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define BASENAME "tst-realpath-toolong." ++ ++int ++do_test (void) ++{ ++ char *base = support_create_and_chdir_toolong_temp_directory (BASENAME); ++ ++ char buf[PATH_MAX + 1]; ++ const char *res = realpath (".", buf); ++ ++ /* canonicalize.c states that if the real path is >= PATH_MAX, then ++ realpath returns NULL and sets ENAMETOOLONG. */ ++ TEST_VERIFY (res == NULL); ++ TEST_VERIFY (errno == ENAMETOOLONG); ++ ++ free (base); ++ return 0; ++} ++ ++#include +-- +2.27.0 + diff --git a/riscv-Drop-reliance-on-_GLOBAL_OFFSET_TABLE_-0.patch b/riscv-Drop-reliance-on-_GLOBAL_OFFSET_TABLE_-0.patch new file mode 100644 index 0000000000000000000000000000000000000000..a45f186a092d107a2ba305ececa180f2e3e8c3b0 --- /dev/null +++ b/riscv-Drop-reliance-on-_GLOBAL_OFFSET_TABLE_-0.patch @@ -0,0 +1,60 @@ +From 34b4624b04fc8f038b2c329ca7560197320615b4 Mon Sep 17 00:00:00 2001 +From: Fangrui Song +Date: Wed, 18 Aug 2021 10:01:31 -0700 +Subject: [PATCH] riscv: Drop reliance on _GLOBAL_OFFSET_TABLE_[0] + +&__ehdr_start is a better way to get the load address. + +This is similar to commits b37b75d269883a2c553bb7019a813094eb4e2dd1 +(x86-64) and 43d06ed218fc8be58987bdfd00e21e5720f0b862 (aarch64). + +Reviewed-by: Palmer Dabbelt +--- + sysdeps/riscv/dl-machine.h | 21 ++++++++++----------- + 1 file changed, 10 insertions(+), 11 deletions(-) + +diff --git a/sysdeps/riscv/dl-machine.h b/sysdeps/riscv/dl-machine.h +index aedf69f..5b07461 100644 +--- a/sysdeps/riscv/dl-machine.h ++++ b/sysdeps/riscv/dl-machine.h +@@ -76,27 +76,26 @@ elf_machine_matches_host (const ElfW(Ehdr) *ehdr) + return 1; + } + ++/* Return the run-time load address of the shared object. */ ++static inline ElfW(Addr) ++elf_machine_load_address (void) ++{ ++ extern const ElfW(Ehdr) __ehdr_start attribute_hidden; ++ return (ElfW(Addr)) &__ehdr_start; ++} ++ + /* Return the link-time address of _DYNAMIC. */ + static inline ElfW(Addr) + elf_machine_dynamic (void) + { +- extern ElfW(Addr) _GLOBAL_OFFSET_TABLE_ __attribute__ ((visibility ("hidden"))); +- return _GLOBAL_OFFSET_TABLE_; ++ extern ElfW(Dyn) _DYNAMIC[] attribute_hidden; ++ return (ElfW(Addr)) _DYNAMIC - elf_machine_load_address (); + } + + #define STRINGXP(X) __STRING (X) + #define STRINGXV(X) STRINGV_ (X) + #define STRINGV_(...) # __VA_ARGS__ + +-/* Return the run-time load address of the shared object. */ +-static inline ElfW(Addr) +-elf_machine_load_address (void) +-{ +- ElfW(Addr) load_addr; +- asm ("lla %0, _DYNAMIC" : "=r" (load_addr)); +- return load_addr - elf_machine_dynamic (); +-} +- + /* Initial entry point code for the dynamic linker. + The C function `_dl_start' is the real entry point; + its return value is the user program's entry point. */ +-- +1.8.3.1 + diff --git a/rseq-Linux-Use-ptrdiff_t-for-__rseq_offset.patch b/rseq-Linux-Use-ptrdiff_t-for-__rseq_offset.patch new file mode 100644 index 0000000000000000000000000000000000000000..1485892f37faf391b5f1ec0c9309eca52246663e --- /dev/null +++ b/rseq-Linux-Use-ptrdiff_t-for-__rseq_offset.patch @@ -0,0 +1,197 @@ +From 6cb5cc084432eba1f2215ec7c9816b748c32182a Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Wed, 2 Feb 2022 22:37:20 +0100 +Subject: [PATCH 9/9] Linux: Use ptrdiff_t for __rseq_offset + +This matches the data size initial-exec relocations use on most +targets. + +Reviewed-by: Mathieu Desnoyers +Reviewed-by: Carlos O'Donell +--- + manual/threads.texi | 2 +- + sysdeps/nptl/dl-tls_init_tp.c | 4 ++-- + sysdeps/unix/sysv/linux/aarch64/ld.abilist | 2 +- + sysdeps/unix/sysv/linux/alpha/ld.abilist | 2 +- + sysdeps/unix/sysv/linux/ia64/ld.abilist | 2 +- + sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist | 2 +- + sysdeps/unix/sysv/linux/powerpc/powerpc64/be/ld.abilist | 2 +- + sysdeps/unix/sysv/linux/powerpc/powerpc64/le/ld.abilist | 2 +- + sysdeps/unix/sysv/linux/riscv/rv64/ld.abilist | 2 +- + sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist | 2 +- + sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist | 2 +- + sysdeps/unix/sysv/linux/sys/rseq.h | 3 ++- + sysdeps/unix/sysv/linux/x86_64/64/ld.abilist | 2 +- + 13 files changed, 15 insertions(+), 14 deletions(-) + +diff --git a/manual/threads.texi b/manual/threads.texi +index ab44a92c..4b9fc946 100644 +--- a/manual/threads.texi ++++ b/manual/threads.texi +@@ -1004,7 +1004,7 @@ The manual for the @code{rseq} system call can be found + at @uref{https://git.kernel.org/pub/scm/libs/librseq/librseq.git/tree/doc/man/rseq.2}. + @end deftp + +-@deftypevar {int} __rseq_offset ++@deftypevar {ptrdiff_t} __rseq_offset + @standards{Linux, sys/rseq.h} + This variable contains the offset between the thread pointer (as defined + by @code{__builtin_thread_pointer} or the thread pointer register for +diff --git a/sysdeps/nptl/dl-tls_init_tp.c b/sysdeps/nptl/dl-tls_init_tp.c +index 4a73927f..86e87c7d 100644 +--- a/sysdeps/nptl/dl-tls_init_tp.c ++++ b/sysdeps/nptl/dl-tls_init_tp.c +@@ -46,7 +46,7 @@ rtld_mutex_dummy (pthread_mutex_t *lock) + + const unsigned int __rseq_flags; + const unsigned int __rseq_size attribute_relro; +-const int __rseq_offset attribute_relro; ++const ptrdiff_t __rseq_offset attribute_relro; + + void + __tls_pre_init_tp (void) +@@ -119,7 +119,7 @@ __tls_init_tp (void) + all targets support __thread_pointer, so set __rseq_offset only + if thre rseq registration may have happened because RSEQ_SIG is + defined. */ +- extern int offset __asm__ ("__rseq_offset"); ++ extern ptrdiff_t offset __asm__ ("__rseq_offset"); + offset = (char *) &pd->rseq_area - (char *) __thread_pointer (); + #endif + } +diff --git a/sysdeps/unix/sysv/linux/aarch64/ld.abilist b/sysdeps/unix/sysv/linux/aarch64/ld.abilist +index bf4d4f9b..5151c078 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/aarch64/ld.abilist +@@ -5,5 +5,5 @@ GLIBC_2.17 _dl_mcount F + GLIBC_2.17 _r_debug D 0x28 + GLIBC_2.34 __rtld_version_placeholder F + GLIBC_2.35 __rseq_flags D 0x4 +-GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_offset D 0x8 + GLIBC_2.35 __rseq_size D 0x4 +diff --git a/sysdeps/unix/sysv/linux/alpha/ld.abilist b/sysdeps/unix/sysv/linux/alpha/ld.abilist +index a23325a5..3e296c54 100644 +--- a/sysdeps/unix/sysv/linux/alpha/ld.abilist ++++ b/sysdeps/unix/sysv/linux/alpha/ld.abilist +@@ -4,6 +4,6 @@ GLIBC_2.1 _dl_mcount F + GLIBC_2.3 __tls_get_addr F + GLIBC_2.34 __rtld_version_placeholder F + GLIBC_2.35 __rseq_flags D 0x4 +-GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_offset D 0x8 + GLIBC_2.35 __rseq_size D 0x4 + GLIBC_2.4 __stack_chk_guard D 0x8 +diff --git a/sysdeps/unix/sysv/linux/ia64/ld.abilist b/sysdeps/unix/sysv/linux/ia64/ld.abilist +index 8ccb5be9..5471b24d 100644 +--- a/sysdeps/unix/sysv/linux/ia64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/ia64/ld.abilist +@@ -4,5 +4,5 @@ GLIBC_2.2 _r_debug D 0x28 + GLIBC_2.3 __tls_get_addr F + GLIBC_2.34 __rtld_version_placeholder F + GLIBC_2.35 __rseq_flags D 0x4 +-GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_offset D 0x8 + GLIBC_2.35 __rseq_size D 0x4 +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist +index 37a47ebc..f26e594a 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist +@@ -4,6 +4,6 @@ GLIBC_2.2 _dl_mcount F + GLIBC_2.3 __tls_get_addr F + GLIBC_2.34 __rtld_version_placeholder F + GLIBC_2.35 __rseq_flags D 0x4 +-GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_offset D 0x8 + GLIBC_2.35 __rseq_size D 0x4 + GLIBC_2.4 __stack_chk_guard D 0x8 +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/ld.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/ld.abilist +index da24dc7f..21f472e6 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/ld.abilist ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/ld.abilist +@@ -6,5 +6,5 @@ GLIBC_2.3 _dl_mcount F + GLIBC_2.3 _r_debug D 0x28 + GLIBC_2.34 __rtld_version_placeholder F + GLIBC_2.35 __rseq_flags D 0x4 +-GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_offset D 0x8 + GLIBC_2.35 __rseq_size D 0x4 +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/ld.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/ld.abilist +index b9ae89ae..9c9c4045 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/ld.abilist ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/ld.abilist +@@ -6,5 +6,5 @@ GLIBC_2.22 __tls_get_addr_opt F + GLIBC_2.23 __parse_hwcap_and_convert_at_platform F + GLIBC_2.34 __rtld_version_placeholder F + GLIBC_2.35 __rseq_flags D 0x4 +-GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_offset D 0x8 + GLIBC_2.35 __rseq_size D 0x4 +diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/ld.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/ld.abilist +index 48431c91..a7758a0e 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/riscv/rv64/ld.abilist +@@ -5,5 +5,5 @@ GLIBC_2.27 _dl_mcount F + GLIBC_2.27 _r_debug D 0x28 + GLIBC_2.34 __rtld_version_placeholder F + GLIBC_2.35 __rseq_flags D 0x4 +-GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_offset D 0x8 + GLIBC_2.35 __rseq_size D 0x4 +diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist +index 117d1430..78d07160 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist +@@ -4,5 +4,5 @@ GLIBC_2.2 _r_debug D 0x28 + GLIBC_2.3 __tls_get_offset F + GLIBC_2.34 __rtld_version_placeholder F + GLIBC_2.35 __rseq_flags D 0x4 +-GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_offset D 0x8 + GLIBC_2.35 __rseq_size D 0x4 +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist +index 8ccb5be9..5471b24d 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist +@@ -4,5 +4,5 @@ GLIBC_2.2 _r_debug D 0x28 + GLIBC_2.3 __tls_get_addr F + GLIBC_2.34 __rtld_version_placeholder F + GLIBC_2.35 __rseq_flags D 0x4 +-GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_offset D 0x8 + GLIBC_2.35 __rseq_size D 0x4 +diff --git a/sysdeps/unix/sysv/linux/sys/rseq.h b/sysdeps/unix/sysv/linux/sys/rseq.h +index 1215b5d0..791ed831 100644 +--- a/sysdeps/unix/sysv/linux/sys/rseq.h ++++ b/sysdeps/unix/sysv/linux/sys/rseq.h +@@ -21,6 +21,7 @@ + /* Architecture-specific rseq signature. */ + #include + ++#include + #include + #include + #include +@@ -172,7 +173,7 @@ struct rseq + #endif /* __GLIBC_HAVE_KERNEL_RSEQ */ + + /* Offset from the thread pointer to the rseq area. */ +-extern const int __rseq_offset; ++extern const ptrdiff_t __rseq_offset; + + /* Size of the registered rseq area. 0 if the registration was + unsuccessful. */ +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist b/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist +index ae622bdf..5a8bd322 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist +@@ -4,5 +4,5 @@ GLIBC_2.2.5 _r_debug D 0x28 + GLIBC_2.3 __tls_get_addr F + GLIBC_2.34 __rtld_version_placeholder F + GLIBC_2.35 __rseq_flags D 0x4 +-GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_offset D 0x8 + GLIBC_2.35 __rseq_size D 0x4 +-- +2.23.0 + diff --git a/rseq-Linux-Use-rseq-to-accelerate-sched_getcpu.patch b/rseq-Linux-Use-rseq-to-accelerate-sched_getcpu.patch new file mode 100644 index 0000000000000000000000000000000000000000..3e7548cb9192076b18056216a7dcc92e5be2be10 --- /dev/null +++ b/rseq-Linux-Use-rseq-to-accelerate-sched_getcpu.patch @@ -0,0 +1,48 @@ +From 00bae0eb5212a1ec4e8b4b90294937903628e7ce Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Thu, 9 Dec 2021 09:49:32 +0100 +Subject: [PATCH 5/9] Linux: Use rseq to accelerate sched_getcpu + +Co-Authored-By: Mathieu Desnoyers +Reviewed-by: Szabolcs Nagy +--- + sysdeps/unix/sysv/linux/sched_getcpu.c | 19 +++++++++++++++++-- + 1 file changed, 17 insertions(+), 2 deletions(-) + +diff --git a/sysdeps/unix/sysv/linux/sched_getcpu.c b/sysdeps/unix/sysv/linux/sched_getcpu.c +index c41e986f..6f78edae 100644 +--- a/sysdeps/unix/sysv/linux/sched_getcpu.c ++++ b/sysdeps/unix/sysv/linux/sched_getcpu.c +@@ -20,8 +20,8 @@ + #include + #include + +-int +-sched_getcpu (void) ++static int ++vsyscall_sched_getcpu (void) + { + unsigned int cpu; + int r = -1; +@@ -32,3 +32,18 @@ sched_getcpu (void) + #endif + return r == -1 ? r : cpu; + } ++ ++#ifdef RSEQ_SIG ++int ++sched_getcpu (void) ++{ ++ int cpu_id = THREAD_GETMEM_VOLATILE (THREAD_SELF, rseq_area.cpu_id); ++ return __glibc_likely (cpu_id >= 0) ? cpu_id : vsyscall_sched_getcpu (); ++} ++#else /* RSEQ_SIG */ ++int ++sched_getcpu (void) ++{ ++ return vsyscall_sched_getcpu (); ++} ++#endif /* RSEQ_SIG */ +-- +2.23.0 + diff --git a/rseq-nptl-Add-glibc.pthread.rseq-tunable-to-control-rseq-.patch b/rseq-nptl-Add-glibc.pthread.rseq-tunable-to-control-rseq-.patch new file mode 100644 index 0000000000000000000000000000000000000000..8e5675de2297d19d106ef7d5ae9be18f0c262bef --- /dev/null +++ b/rseq-nptl-Add-glibc.pthread.rseq-tunable-to-control-rseq-.patch @@ -0,0 +1,300 @@ +From ff1e1631665651ceb8b4b226ec725140c7420e8c Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Thu, 9 Dec 2021 09:49:32 +0100 +Subject: [PATCH 6/9] nptl: Add glibc.pthread.rseq tunable to control rseq + registration + +This tunable allows applications to register the rseq area instead +of glibc. + +Reviewed-by: Szabolcs Nagy +Reviewed-by: Siddhesh Poyarekar +----- +change: +Since rseq is a big feature and have changed code behavior quite a lot, +disable rseq by default to reduce potential conflicts. + +sysdeps/nptl/dl-tunables.list: + default: 1 -> default: 0 + +--- + manual/tunables.texi | 10 +++ + nptl/pthread_create.c | 10 ++- + sysdeps/nptl/dl-tls_init_tp.c | 11 ++- + sysdeps/nptl/dl-tunables.list | 6 ++ + sysdeps/nptl/internaltypes.h | 1 + + sysdeps/unix/sysv/linux/Makefile | 8 ++ + sysdeps/unix/sysv/linux/rseq-internal.h | 19 +++-- + sysdeps/unix/sysv/linux/tst-rseq-disable.c | 89 ++++++++++++++++++++++ + 8 files changed, 145 insertions(+), 9 deletions(-) + create mode 100644 sysdeps/unix/sysv/linux/tst-rseq-disable.c + +diff --git a/manual/tunables.texi b/manual/tunables.texi +index 658547c6..1f5c4102 100644 +--- a/manual/tunables.texi ++++ b/manual/tunables.texi +@@ -413,6 +413,16 @@ The value is measured in bytes. The default is @samp{41943040} + (fourty mibibytes). + @end deftp + ++@deftp Tunable glibc.pthread.rseq ++The @code{glibc.pthread.rseq} tunable can be set to @samp{0}, to disable ++restartable sequences support in @theglibc{}. This enables applications ++to perform direct restartable sequence registration with the kernel. ++The default is @samp{1}, which means that @theglibc{} performs ++registration on behalf of the application. ++ ++Restartable sequences are a Linux-specific extension. ++@end deftp ++ + @node Hardware Capability Tunables + @section Hardware Capability Tunables + @cindex hardware capability tunables +diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c +index d2b40924..f405fa35 100644 +--- a/nptl/pthread_create.c ++++ b/nptl/pthread_create.c +@@ -369,7 +369,10 @@ start_thread (void *arg) + __ctype_init (); + + /* Register rseq TLS to the kernel. */ +- rseq_register_current_thread (pd); ++ { ++ bool do_rseq = THREAD_GETMEM (pd, flags) & ATTR_FLAG_DO_RSEQ; ++ rseq_register_current_thread (pd, do_rseq); ++ } + + #ifndef __ASSUME_SET_ROBUST_LIST + if (__nptl_set_robust_list_avail) +@@ -678,6 +681,11 @@ __pthread_create_2_1 (pthread_t *newthread, const pthread_attr_t *attr, + pd->flags = ((iattr->flags & ~(ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET)) + | (self->flags & (ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET))); + ++ /* Inherit rseq registration state. Without seccomp filters, rseq ++ registration will either always fail or always succeed. */ ++ if ((int) THREAD_GETMEM_VOLATILE (self, rseq_area.cpu_id) >= 0) ++ pd->flags |= ATTR_FLAG_DO_RSEQ; ++ + /* Initialize the field for the ID of the thread which is waiting + for us. This is a self-reference in case the thread is created + detached. */ +diff --git a/sysdeps/nptl/dl-tls_init_tp.c b/sysdeps/nptl/dl-tls_init_tp.c +index fedb876f..b39dfbff 100644 +--- a/sysdeps/nptl/dl-tls_init_tp.c ++++ b/sysdeps/nptl/dl-tls_init_tp.c +@@ -23,6 +23,9 @@ + #include + #include + ++#define TUNABLE_NAMESPACE pthread ++#include ++ + #ifndef __ASSUME_SET_ROBUST_LIST + bool __nptl_set_robust_list_avail; + rtld_hidden_data_def (__nptl_set_robust_list_avail) +@@ -92,7 +95,13 @@ __tls_init_tp (void) + } + } + +- rseq_register_current_thread (pd); ++ { ++ bool do_rseq = true; ++#if HAVE_TUNABLES ++ do_rseq = TUNABLE_GET (rseq, int, NULL); ++#endif ++ rseq_register_current_thread (pd, do_rseq); ++ } + + /* Set initial thread's stack block from 0 up to __libc_stack_end. + It will be bigger than it actually is, but for unwind.c/pt-longjmp.c +diff --git a/sysdeps/nptl/dl-tunables.list b/sysdeps/nptl/dl-tunables.list +index ac5d0532..d24f4be0 100644 +--- a/sysdeps/nptl/dl-tunables.list ++++ b/sysdeps/nptl/dl-tunables.list +@@ -27,5 +27,11 @@ glibc { + type: SIZE_T + default: 41943040 + } ++ rseq { ++ type: INT_32 ++ minval: 0 ++ maxval: 1 ++ default: 0 ++ } + } + } +diff --git a/sysdeps/nptl/internaltypes.h b/sysdeps/nptl/internaltypes.h +index 50a2ad19..8205c6d1 100644 +--- a/sysdeps/nptl/internaltypes.h ++++ b/sysdeps/nptl/internaltypes.h +@@ -49,6 +49,7 @@ struct pthread_attr + #define ATTR_FLAG_OLDATTR 0x0010 + #define ATTR_FLAG_SCHED_SET 0x0020 + #define ATTR_FLAG_POLICY_SET 0x0040 ++#define ATTR_FLAG_DO_RSEQ 0x0080 + + /* Used to allocate a pthread_attr_t object which is also accessed + internally. */ +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index f103a964..0657f400 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -135,6 +135,12 @@ tests-internal += \ + tst-sigcontext-get_pc \ + # tests-internal + ++ifneq (no,$(have-tunables)) ++tests-internal += \ ++ tst-rseq-disable \ ++ # tests-internal $(have-tunables) ++endif ++ + tests-time64 += \ + tst-adjtimex-time64 \ + tst-clock_adjtime-time64 \ +@@ -226,6 +232,8 @@ $(objpfx)tst-mman-consts.out: ../sysdeps/unix/sysv/linux/tst-mman-consts.py + < /dev/null > $@ 2>&1; $(evaluate-test) + $(objpfx)tst-mman-consts.out: $(sysdeps-linux-python-deps) + ++tst-rseq-disable-ENV = GLIBC_TUNABLES=glibc.pthread.rseq=0 ++ + endif # $(subdir) == misc + + ifeq ($(subdir),time) +diff --git a/sysdeps/unix/sysv/linux/rseq-internal.h b/sysdeps/unix/sysv/linux/rseq-internal.h +index 909f5478..15bc7ffd 100644 +--- a/sysdeps/unix/sysv/linux/rseq-internal.h ++++ b/sysdeps/unix/sysv/linux/rseq-internal.h +@@ -21,22 +21,27 @@ + #include + #include + #include ++#include + #include + #include + + #ifdef RSEQ_SIG + static inline void +-rseq_register_current_thread (struct pthread *self) ++rseq_register_current_thread (struct pthread *self, bool do_rseq) + { +- int ret = INTERNAL_SYSCALL_CALL (rseq, +- &self->rseq_area, sizeof (self->rseq_area), +- 0, RSEQ_SIG); +- if (INTERNAL_SYSCALL_ERROR_P (ret)) +- THREAD_SETMEM (self, rseq_area.cpu_id, RSEQ_CPU_ID_REGISTRATION_FAILED); ++ if (do_rseq) ++ { ++ int ret = INTERNAL_SYSCALL_CALL (rseq, &self->rseq_area, ++ sizeof (self->rseq_area), ++ 0, RSEQ_SIG); ++ if (!INTERNAL_SYSCALL_ERROR_P (ret)) ++ return; ++ } ++ THREAD_SETMEM (self, rseq_area.cpu_id, RSEQ_CPU_ID_REGISTRATION_FAILED); + } + #else /* RSEQ_SIG */ + static inline void +-rseq_register_current_thread (struct pthread *self) ++rseq_register_current_thread (struct pthread *self, bool do_rseq) + { + THREAD_SETMEM (self, rseq_area.cpu_id, RSEQ_CPU_ID_REGISTRATION_FAILED); + } +diff --git a/sysdeps/unix/sysv/linux/tst-rseq-disable.c b/sysdeps/unix/sysv/linux/tst-rseq-disable.c +new file mode 100644 +index 00000000..000e3518 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-rseq-disable.c +@@ -0,0 +1,89 @@ ++/* Test disabling of rseq registration via tunable. ++ Copyright (C) 2021 Free Software Foundation, Inc. ++ ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef RSEQ_SIG ++ ++/* Check that rseq can be registered and has not been taken by glibc. */ ++static void ++check_rseq_disabled (void) ++{ ++ struct pthread *pd = THREAD_SELF; ++ TEST_COMPARE ((int) pd->rseq_area.cpu_id, RSEQ_CPU_ID_REGISTRATION_FAILED); ++ ++ int ret = syscall (__NR_rseq, &pd->rseq_area, sizeof (pd->rseq_area), ++ 0, RSEQ_SIG); ++ if (ret == 0) ++ { ++ ret = syscall (__NR_rseq, &pd->rseq_area, sizeof (pd->rseq_area), ++ RSEQ_FLAG_UNREGISTER, RSEQ_SIG); ++ TEST_COMPARE (ret, 0); ++ pd->rseq_area.cpu_id = RSEQ_CPU_ID_REGISTRATION_FAILED; ++ } ++ else ++ { ++ TEST_VERIFY (errno != -EINVAL); ++ TEST_VERIFY (errno != -EBUSY); ++ } ++} ++ ++static void * ++thread_func (void *ignored) ++{ ++ check_rseq_disabled (); ++ return NULL; ++} ++ ++static void ++proc_func (void *ignored) ++{ ++ check_rseq_disabled (); ++} ++ ++static int ++do_test (void) ++{ ++ puts ("info: checking main thread"); ++ check_rseq_disabled (); ++ ++ puts ("info: checking main thread (2)"); ++ check_rseq_disabled (); ++ ++ puts ("info: checking new thread"); ++ xpthread_join (xpthread_create (NULL, thread_func, NULL)); ++ ++ puts ("info: checking subprocess"); ++ support_isolate_in_subprocess (proc_func, NULL); ++ ++ return 0; ++} ++#else /* !RSEQ_SIG */ ++static int ++do_test (void) ++{ ++ FAIL_UNSUPPORTED ("glibc does not define RSEQ_SIG, skipping test"); ++} ++#endif ++ ++#include +-- +2.23.0 + diff --git a/rseq-nptl-Add-public-rseq-symbols-and-sys-rseq.h.patch b/rseq-nptl-Add-public-rseq-symbols-and-sys-rseq.h.patch new file mode 100644 index 0000000000000000000000000000000000000000..f4311c5e645114c6a0d86920048983cd8eacbf95 --- /dev/null +++ b/rseq-nptl-Add-public-rseq-symbols-and-sys-rseq.h.patch @@ -0,0 +1,692 @@ +From e3291e074ff67a8cc2630ab6175976f875d61a14 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Thu, 17 Feb 2022 14:56:12 +0800 +Subject: [PATCH 7/9] nptl: Add public rseq symbols and + +The relationship between the thread pointer and the rseq area +is made explicit. The constant offset can be used by JIT compilers +to optimize rseq access (e.g., for really fast sched_getcpu). + +Extensibility is provided through __rseq_size and __rseq_flags. +(In the future, the kernel could request a different rseq size +via the auxiliary vector.) + +Co-Authored-By: Mathieu Desnoyers +Reviewed-by: Szabolcs Nagy +----- +conflicts: + context conflicts +--- + NEWS | 11 +++ + manual/threads.texi | 81 +++++++++++++++++++ + sysdeps/nptl/dl-tls_init_tp.c | 23 +++++- + sysdeps/unix/sysv/linux/Makefile | 3 +- + sysdeps/unix/sysv/linux/Versions | 5 ++ + sysdeps/unix/sysv/linux/aarch64/ld.abilist | 3 + + sysdeps/unix/sysv/linux/alpha/ld.abilist | 3 + + sysdeps/unix/sysv/linux/arc/ld.abilist | 3 + + sysdeps/unix/sysv/linux/arm/be/ld.abilist | 3 + + sysdeps/unix/sysv/linux/arm/le/ld.abilist | 3 + + sysdeps/unix/sysv/linux/csky/ld.abilist | 3 + + sysdeps/unix/sysv/linux/hppa/ld.abilist | 3 + + sysdeps/unix/sysv/linux/i386/ld.abilist | 3 + + sysdeps/unix/sysv/linux/ia64/ld.abilist | 3 + + .../unix/sysv/linux/m68k/coldfire/ld.abilist | 3 + + .../unix/sysv/linux/m68k/m680x0/ld.abilist | 3 + + sysdeps/unix/sysv/linux/microblaze/ld.abilist | 3 + + .../unix/sysv/linux/mips/mips32/ld.abilist | 3 + + .../sysv/linux/mips/mips64/n32/ld.abilist | 3 + + .../sysv/linux/mips/mips64/n64/ld.abilist | 3 + + sysdeps/unix/sysv/linux/nios2/ld.abilist | 3 + + .../sysv/linux/powerpc/powerpc32/ld.abilist | 3 + + .../linux/powerpc/powerpc64/be/ld.abilist | 3 + + .../linux/powerpc/powerpc64/le/ld.abilist | 3 + + sysdeps/unix/sysv/linux/riscv/rv32/ld.abilist | 3 + + sysdeps/unix/sysv/linux/riscv/rv64/ld.abilist | 3 + + sysdeps/unix/sysv/linux/rseq-internal.h | 8 +- + .../unix/sysv/linux/s390/s390-32/ld.abilist | 3 + + .../unix/sysv/linux/s390/s390-64/ld.abilist | 3 + + sysdeps/unix/sysv/linux/sh/be/ld.abilist | 3 + + sysdeps/unix/sysv/linux/sh/le/ld.abilist | 3 + + .../unix/sysv/linux/sparc/sparc32/ld.abilist | 3 + + .../unix/sysv/linux/sparc/sparc64/ld.abilist | 3 + + sysdeps/unix/sysv/linux/sys/rseq.h | 10 +++ + sysdeps/unix/sysv/linux/tst-rseq-disable.c | 6 ++ + sysdeps/unix/sysv/linux/tst-rseq.c | 8 ++ + sysdeps/unix/sysv/linux/x86_64/64/ld.abilist | 3 + + sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist | 3 + + 38 files changed, 237 insertions(+), 5 deletions(-) + +diff --git a/NEWS b/NEWS +index ffae154a..1b0ee549 100644 +--- a/NEWS ++++ b/NEWS +@@ -129,6 +129,17 @@ Major new features: + than or equal to a given integer. This function is a GNU extension, + although Solaris also provides a similar function. + ++* Support for automatically registering threads with the Linux rseq ++ system call has been added. This system call is implemented starting ++ from Linux 4.18. The Restartable Sequences ABI accelerates user-space ++ operations on per-cpu data. It allows user-space to perform updates ++ on per-cpu data without requiring heavy-weight atomic operations. ++ Automatically registering threads allows all libraries, including ++ libc, to make immediate use of the rseq support by using the ++ documented ABI, via the __rseq_flags, __rseq_offset, and __rseq_size ++ variables. The GNU C Library manual has details on integration of ++ Restartable Sequences. ++ + Deprecated and removed features, and other changes affecting compatibility: + + * The function pthread_mutex_consistent_np has been deprecated; programs +diff --git a/manual/threads.texi b/manual/threads.texi +index 06b6b277..ab44a92c 100644 +--- a/manual/threads.texi ++++ b/manual/threads.texi +@@ -629,6 +629,8 @@ the standard. + * Waiting with Explicit Clocks:: Functions for waiting with an + explicit clock specification. + * Single-Threaded:: Detecting single-threaded execution. ++* Restartable Sequences:: Linux-specific restartable sequences ++ integration. + @end menu + + @node Default Thread Attributes +@@ -958,6 +960,85 @@ application-created thread because future versions of @theglibc{} may + create background threads after the first thread has been created, and + the application has no way of knowning that these threads are present. + ++@node Restartable Sequences ++@subsubsection Restartable Sequences ++ ++This section describes restartable sequences integration for ++@theglibc{}. This functionality is only available on Linux. ++ ++@deftp {Data Type} {struct rseq} ++@standards{Linux, sys/rseq.h} ++The type of the restartable sequences area. Future versions ++of Linux may add additional fields to the end of this structure. ++ ++ ++Users need to obtain the address of the restartable sequences area using ++the thread pointer and the @code{__rseq_offset} variable, described ++below. ++ ++One use of the restartable sequences area is to read the current CPU ++number from its @code{cpu_id} field, as an inline version of ++@code{sched_getcpu}. @Theglibc{} sets the @code{cpu_id} field to ++@code{RSEQ_CPU_ID_REGISTRATION_FAILED} if registration failed or was ++explicitly disabled. ++ ++Furthermore, users can store the address of a @code{struct rseq_cs} ++object into the @code{rseq_cs} field of @code{struct rseq}, thus ++informing the kernel that the thread enters a restartable sequence ++critical section. This pointer and the code areas it itself points to ++must not be left pointing to memory areas which are freed or re-used. ++Several approaches can guarantee this. If the application or library ++can guarantee that the memory used to hold the @code{struct rseq_cs} and ++the code areas it refers to are never freed or re-used, no special ++action must be taken. Else, before that memory is re-used of freed, the ++application is responsible for setting the @code{rseq_cs} field to ++@code{NULL} in each thread's restartable sequence area to guarantee that ++it does not leak dangling references. Because the application does not ++typically have knowledge of libraries' use of restartable sequences, it ++is recommended that libraries using restartable sequences which may end ++up freeing or re-using their memory set the @code{rseq_cs} field to ++@code{NULL} before returning from library functions which use ++restartable sequences. ++ ++The manual for the @code{rseq} system call can be found ++at @uref{https://git.kernel.org/pub/scm/libs/librseq/librseq.git/tree/doc/man/rseq.2}. ++@end deftp ++ ++@deftypevar {int} __rseq_offset ++@standards{Linux, sys/rseq.h} ++This variable contains the offset between the thread pointer (as defined ++by @code{__builtin_thread_pointer} or the thread pointer register for ++the architecture) and the restartable sequences area. This value is the ++same for all threads in the process. If the restartable sequences area ++is located at a lower address than the location to which the thread ++pointer points, the value is negative. ++@end deftypevar ++ ++@deftypevar {unsigned int} __rseq_size ++@standards{Linux, sys/rseq.h} ++This variable is either zero (if restartable sequence registration ++failed or has been disabled) or the size of the restartable sequence ++registration. This can be different from the size of @code{struct rseq} ++if the kernel has extended the size of the registration. If ++registration is successful, @code{__rseq_size} is at least 32 (the ++initial size of @code{struct rseq}). ++@end deftypevar ++ ++@deftypevar {unsigned int} __rseq_flags ++@standards{Linux, sys/rseq.h} ++The flags used during restartable sequence registration with the kernel. ++Currently zero. ++@end deftypevar ++ ++@deftypevr Macro int RSEQ_SIG ++@standards{Linux, sys/rseq.h} ++Each supported architecture provides a @code{RSEQ_SIG} macro in ++@file{sys/rseq.h} which contains a signature. That signature is ++expected to be present in the code before each restartable sequences ++abort handler. Failure to provide the expected signature may terminate ++the process with a segmentation fault. ++@end deftypevr ++ + @c FIXME these are undocumented: + @c pthread_atfork + @c pthread_attr_destroy +diff --git a/sysdeps/nptl/dl-tls_init_tp.c b/sysdeps/nptl/dl-tls_init_tp.c +index b39dfbff..4a73927f 100644 +--- a/sysdeps/nptl/dl-tls_init_tp.c ++++ b/sysdeps/nptl/dl-tls_init_tp.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + #define TUNABLE_NAMESPACE pthread + #include +@@ -43,6 +44,10 @@ rtld_mutex_dummy (pthread_mutex_t *lock) + } + #endif + ++const unsigned int __rseq_flags; ++const unsigned int __rseq_size attribute_relro; ++const int __rseq_offset attribute_relro; ++ + void + __tls_pre_init_tp (void) + { +@@ -100,7 +105,23 @@ __tls_init_tp (void) + #if HAVE_TUNABLES + do_rseq = TUNABLE_GET (rseq, int, NULL); + #endif +- rseq_register_current_thread (pd, do_rseq); ++ if (rseq_register_current_thread (pd, do_rseq)) ++ { ++ /* We need a writable view of the variables. They are in ++ .data.relro and are not yet write-protected. */ ++ extern unsigned int size __asm__ ("__rseq_size"); ++ size = sizeof (pd->rseq_area); ++ } ++ ++#ifdef RSEQ_SIG ++ /* This should be a compile-time constant, but the current ++ infrastructure makes it difficult to determine its value. Not ++ all targets support __thread_pointer, so set __rseq_offset only ++ if thre rseq registration may have happened because RSEQ_SIG is ++ defined. */ ++ extern int offset __asm__ ("__rseq_offset"); ++ offset = (char *) &pd->rseq_area - (char *) __thread_pointer (); ++#endif + } + + /* Set initial thread's stack block from 0 up to __libc_stack_end. +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index 0657f400..856a9d58 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -110,7 +110,8 @@ sysdep_headers += sys/mount.h sys/acct.h \ + bits/types/struct_semid64_ds_helper.h \ + bits/types/struct_shmid64_ds.h \ + bits/types/struct_shmid64_ds_helper.h \ +- bits/pthread_stack_min.h bits/pthread_stack_min-dynamic.h ++ bits/pthread_stack_min.h bits/pthread_stack_min-dynamic.h \ ++ sys/rseq.h bits/rseq.h + + tests += tst-clone tst-clone2 tst-clone3 tst-fanotify tst-personality \ + tst-quota tst-sync_file_range tst-sysconf-iov_max tst-ttyname \ +diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions +index 26452f3f..3f8809a1 100644 +--- a/sysdeps/unix/sysv/linux/Versions ++++ b/sysdeps/unix/sysv/linux/Versions +@@ -316,6 +316,11 @@ librt { + } + + ld { ++ GLIBC_2.35 { ++ __rseq_flags; ++ __rseq_offset; ++ __rseq_size; ++ } + GLIBC_PRIVATE { + __nptl_change_stack_perm; + } +diff --git a/sysdeps/unix/sysv/linux/aarch64/ld.abilist b/sysdeps/unix/sysv/linux/aarch64/ld.abilist +index b7196a80..bf4d4f9b 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/aarch64/ld.abilist +@@ -4,3 +4,6 @@ GLIBC_2.17 __tls_get_addr F + GLIBC_2.17 _dl_mcount F + GLIBC_2.17 _r_debug D 0x28 + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 +diff --git a/sysdeps/unix/sysv/linux/alpha/ld.abilist b/sysdeps/unix/sysv/linux/alpha/ld.abilist +index 13f7fc74..a23325a5 100644 +--- a/sysdeps/unix/sysv/linux/alpha/ld.abilist ++++ b/sysdeps/unix/sysv/linux/alpha/ld.abilist +@@ -3,4 +3,7 @@ GLIBC_2.1 __libc_stack_end D 0x8 + GLIBC_2.1 _dl_mcount F + GLIBC_2.3 __tls_get_addr F + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 + GLIBC_2.4 __stack_chk_guard D 0x8 +diff --git a/sysdeps/unix/sysv/linux/arc/ld.abilist b/sysdeps/unix/sysv/linux/arc/ld.abilist +index 7284383a..55f0c2ab 100644 +--- a/sysdeps/unix/sysv/linux/arc/ld.abilist ++++ b/sysdeps/unix/sysv/linux/arc/ld.abilist +@@ -4,3 +4,6 @@ GLIBC_2.32 __tls_get_addr F + GLIBC_2.32 _dl_mcount F + GLIBC_2.32 _r_debug D 0x14 + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 +diff --git a/sysdeps/unix/sysv/linux/arm/be/ld.abilist b/sysdeps/unix/sysv/linux/arm/be/ld.abilist +index 7987bbae..f1da2c63 100644 +--- a/sysdeps/unix/sysv/linux/arm/be/ld.abilist ++++ b/sysdeps/unix/sysv/linux/arm/be/ld.abilist +@@ -1,4 +1,7 @@ + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 + GLIBC_2.4 __libc_stack_end D 0x4 + GLIBC_2.4 __stack_chk_guard D 0x4 + GLIBC_2.4 __tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/arm/le/ld.abilist b/sysdeps/unix/sysv/linux/arm/le/ld.abilist +index 7987bbae..f1da2c63 100644 +--- a/sysdeps/unix/sysv/linux/arm/le/ld.abilist ++++ b/sysdeps/unix/sysv/linux/arm/le/ld.abilist +@@ -1,4 +1,7 @@ + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 + GLIBC_2.4 __libc_stack_end D 0x4 + GLIBC_2.4 __stack_chk_guard D 0x4 + GLIBC_2.4 __tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/csky/ld.abilist b/sysdeps/unix/sysv/linux/csky/ld.abilist +index 4939b206..7f482276 100644 +--- a/sysdeps/unix/sysv/linux/csky/ld.abilist ++++ b/sysdeps/unix/sysv/linux/csky/ld.abilist +@@ -4,3 +4,6 @@ GLIBC_2.29 __tls_get_addr F + GLIBC_2.29 _dl_mcount F + GLIBC_2.29 _r_debug D 0x14 + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 +diff --git a/sysdeps/unix/sysv/linux/hppa/ld.abilist b/sysdeps/unix/sysv/linux/hppa/ld.abilist +index 7cc9ebd7..7f5527fb 100644 +--- a/sysdeps/unix/sysv/linux/hppa/ld.abilist ++++ b/sysdeps/unix/sysv/linux/hppa/ld.abilist +@@ -3,4 +3,7 @@ GLIBC_2.2 _dl_mcount F + GLIBC_2.2 _r_debug D 0x14 + GLIBC_2.3 __tls_get_addr F + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 + GLIBC_2.4 __stack_chk_guard D 0x4 +diff --git a/sysdeps/unix/sysv/linux/i386/ld.abilist b/sysdeps/unix/sysv/linux/i386/ld.abilist +index e8d187b1..9c4a45d8 100644 +--- a/sysdeps/unix/sysv/linux/i386/ld.abilist ++++ b/sysdeps/unix/sysv/linux/i386/ld.abilist +@@ -4,3 +4,6 @@ GLIBC_2.1 _dl_mcount F + GLIBC_2.3 ___tls_get_addr F + GLIBC_2.3 __tls_get_addr F + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 +diff --git a/sysdeps/unix/sysv/linux/ia64/ld.abilist b/sysdeps/unix/sysv/linux/ia64/ld.abilist +index be512265..8ccb5be9 100644 +--- a/sysdeps/unix/sysv/linux/ia64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/ia64/ld.abilist +@@ -3,3 +3,6 @@ GLIBC_2.2 _dl_mcount F + GLIBC_2.2 _r_debug D 0x28 + GLIBC_2.3 __tls_get_addr F + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 +diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/ld.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/ld.abilist +index 7987bbae..f1da2c63 100644 +--- a/sysdeps/unix/sysv/linux/m68k/coldfire/ld.abilist ++++ b/sysdeps/unix/sysv/linux/m68k/coldfire/ld.abilist +@@ -1,4 +1,7 @@ + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 + GLIBC_2.4 __libc_stack_end D 0x4 + GLIBC_2.4 __stack_chk_guard D 0x4 + GLIBC_2.4 __tls_get_addr F +diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/ld.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/ld.abilist +index 4f2854ed..dadbf852 100644 +--- a/sysdeps/unix/sysv/linux/m68k/m680x0/ld.abilist ++++ b/sysdeps/unix/sysv/linux/m68k/m680x0/ld.abilist +@@ -3,4 +3,7 @@ GLIBC_2.1 __libc_stack_end D 0x4 + GLIBC_2.1 _dl_mcount F + GLIBC_2.3 __tls_get_addr F + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 + GLIBC_2.4 __stack_chk_guard D 0x4 +diff --git a/sysdeps/unix/sysv/linux/microblaze/ld.abilist b/sysdeps/unix/sysv/linux/microblaze/ld.abilist +index 9f0fdeca..89a0b7e4 100644 +--- a/sysdeps/unix/sysv/linux/microblaze/ld.abilist ++++ b/sysdeps/unix/sysv/linux/microblaze/ld.abilist +@@ -4,3 +4,6 @@ GLIBC_2.18 __tls_get_addr F + GLIBC_2.18 _dl_mcount F + GLIBC_2.18 _r_debug D 0x14 + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 +diff --git a/sysdeps/unix/sysv/linux/mips/mips32/ld.abilist b/sysdeps/unix/sysv/linux/mips/mips32/ld.abilist +index f750067d..e304d1bb 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/mips/mips32/ld.abilist +@@ -3,4 +3,7 @@ GLIBC_2.2 __libc_stack_end D 0x4 + GLIBC_2.2 _dl_mcount F + GLIBC_2.3 __tls_get_addr F + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 + GLIBC_2.4 __stack_chk_guard D 0x4 +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/ld.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/ld.abilist +index f750067d..e304d1bb 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/ld.abilist +@@ -3,4 +3,7 @@ GLIBC_2.2 __libc_stack_end D 0x4 + GLIBC_2.2 _dl_mcount F + GLIBC_2.3 __tls_get_addr F + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 + GLIBC_2.4 __stack_chk_guard D 0x4 +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist +index 2fba6a9b..37a47ebc 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/ld.abilist +@@ -3,4 +3,7 @@ GLIBC_2.2 __libc_stack_end D 0x8 + GLIBC_2.2 _dl_mcount F + GLIBC_2.3 __tls_get_addr F + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 + GLIBC_2.4 __stack_chk_guard D 0x8 +diff --git a/sysdeps/unix/sysv/linux/nios2/ld.abilist b/sysdeps/unix/sysv/linux/nios2/ld.abilist +index 57dfad5a..811ae9da 100644 +--- a/sysdeps/unix/sysv/linux/nios2/ld.abilist ++++ b/sysdeps/unix/sysv/linux/nios2/ld.abilist +@@ -4,3 +4,6 @@ GLIBC_2.21 __tls_get_addr F + GLIBC_2.21 _dl_mcount F + GLIBC_2.21 _r_debug D 0x14 + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/ld.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/ld.abilist +index e8966073..5a68aeb9 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/ld.abilist +@@ -5,3 +5,6 @@ GLIBC_2.22 __tls_get_addr_opt F + GLIBC_2.23 __parse_hwcap_and_convert_at_platform F + GLIBC_2.3 __tls_get_addr F + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/ld.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/ld.abilist +index ce0bc639..da24dc7f 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/ld.abilist ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/ld.abilist +@@ -5,3 +5,6 @@ GLIBC_2.3 __tls_get_addr F + GLIBC_2.3 _dl_mcount F + GLIBC_2.3 _r_debug D 0x28 + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/ld.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/ld.abilist +index 65b22674..b9ae89ae 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/ld.abilist ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/ld.abilist +@@ -5,3 +5,6 @@ GLIBC_2.17 _r_debug D 0x28 + GLIBC_2.22 __tls_get_addr_opt F + GLIBC_2.23 __parse_hwcap_and_convert_at_platform F + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 +diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/ld.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/ld.abilist +index 5ad4c81d..06836887 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/riscv/rv32/ld.abilist +@@ -4,3 +4,6 @@ GLIBC_2.33 __tls_get_addr F + GLIBC_2.33 _dl_mcount F + GLIBC_2.33 _r_debug D 0x14 + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 +diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/ld.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/ld.abilist +index 479efdea..48431c91 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/riscv/rv64/ld.abilist +@@ -4,3 +4,6 @@ GLIBC_2.27 __tls_get_addr F + GLIBC_2.27 _dl_mcount F + GLIBC_2.27 _r_debug D 0x28 + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 +diff --git a/sysdeps/unix/sysv/linux/rseq-internal.h b/sysdeps/unix/sysv/linux/rseq-internal.h +index 15bc7ffd..9e8f99fd 100644 +--- a/sysdeps/unix/sysv/linux/rseq-internal.h ++++ b/sysdeps/unix/sysv/linux/rseq-internal.h +@@ -26,7 +26,7 @@ + #include + + #ifdef RSEQ_SIG +-static inline void ++static inline bool + rseq_register_current_thread (struct pthread *self, bool do_rseq) + { + if (do_rseq) +@@ -35,15 +35,17 @@ rseq_register_current_thread (struct pthread *self, bool do_rseq) + sizeof (self->rseq_area), + 0, RSEQ_SIG); + if (!INTERNAL_SYSCALL_ERROR_P (ret)) +- return; ++ return true; + } + THREAD_SETMEM (self, rseq_area.cpu_id, RSEQ_CPU_ID_REGISTRATION_FAILED); ++ return false; + } + #else /* RSEQ_SIG */ +-static inline void ++static inline bool + rseq_register_current_thread (struct pthread *self, bool do_rseq) + { + THREAD_SETMEM (self, rseq_area.cpu_id, RSEQ_CPU_ID_REGISTRATION_FAILED); ++ return false; + } + #endif /* RSEQ_SIG */ + +diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/ld.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/ld.abilist +index d5ecb636..c1528839 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/s390/s390-32/ld.abilist +@@ -3,3 +3,6 @@ GLIBC_2.1 __libc_stack_end D 0x4 + GLIBC_2.1 _dl_mcount F + GLIBC_2.3 __tls_get_offset F + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 +diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist +index 62a5e1d9..117d1430 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/s390/s390-64/ld.abilist +@@ -3,3 +3,6 @@ GLIBC_2.2 _dl_mcount F + GLIBC_2.2 _r_debug D 0x28 + GLIBC_2.3 __tls_get_offset F + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 +diff --git a/sysdeps/unix/sysv/linux/sh/be/ld.abilist b/sysdeps/unix/sysv/linux/sh/be/ld.abilist +index 7cc9ebd7..7f5527fb 100644 +--- a/sysdeps/unix/sysv/linux/sh/be/ld.abilist ++++ b/sysdeps/unix/sysv/linux/sh/be/ld.abilist +@@ -3,4 +3,7 @@ GLIBC_2.2 _dl_mcount F + GLIBC_2.2 _r_debug D 0x14 + GLIBC_2.3 __tls_get_addr F + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 + GLIBC_2.4 __stack_chk_guard D 0x4 +diff --git a/sysdeps/unix/sysv/linux/sh/le/ld.abilist b/sysdeps/unix/sysv/linux/sh/le/ld.abilist +index 7cc9ebd7..7f5527fb 100644 +--- a/sysdeps/unix/sysv/linux/sh/le/ld.abilist ++++ b/sysdeps/unix/sysv/linux/sh/le/ld.abilist +@@ -3,4 +3,7 @@ GLIBC_2.2 _dl_mcount F + GLIBC_2.2 _r_debug D 0x14 + GLIBC_2.3 __tls_get_addr F + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 + GLIBC_2.4 __stack_chk_guard D 0x4 +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/ld.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/ld.abilist +index 2e605434..3aac73f3 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/sparc/sparc32/ld.abilist +@@ -3,3 +3,6 @@ GLIBC_2.1 __libc_stack_end D 0x4 + GLIBC_2.1 _dl_mcount F + GLIBC_2.3 __tls_get_addr F + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist +index be512265..8ccb5be9 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/ld.abilist +@@ -3,3 +3,6 @@ GLIBC_2.2 _dl_mcount F + GLIBC_2.2 _r_debug D 0x28 + GLIBC_2.3 __tls_get_addr F + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 +diff --git a/sysdeps/unix/sysv/linux/sys/rseq.h b/sysdeps/unix/sysv/linux/sys/rseq.h +index c8edff50..1215b5d0 100644 +--- a/sysdeps/unix/sysv/linux/sys/rseq.h ++++ b/sysdeps/unix/sysv/linux/sys/rseq.h +@@ -171,4 +171,14 @@ struct rseq + + #endif /* __GLIBC_HAVE_KERNEL_RSEQ */ + ++/* Offset from the thread pointer to the rseq area. */ ++extern const int __rseq_offset; ++ ++/* Size of the registered rseq area. 0 if the registration was ++ unsuccessful. */ ++extern const unsigned int __rseq_size; ++ ++/* Flags used during rseq registration. */ ++extern const unsigned int __rseq_flags; ++ + #endif /* sys/rseq.h */ +diff --git a/sysdeps/unix/sysv/linux/tst-rseq-disable.c b/sysdeps/unix/sysv/linux/tst-rseq-disable.c +index 000e3518..6d73f77e 100644 +--- a/sysdeps/unix/sysv/linux/tst-rseq-disable.c ++++ b/sysdeps/unix/sysv/linux/tst-rseq-disable.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + + #ifdef RSEQ_SIG +@@ -30,6 +31,11 @@ static void + check_rseq_disabled (void) + { + struct pthread *pd = THREAD_SELF; ++ ++ TEST_COMPARE (__rseq_flags, 0); ++ TEST_VERIFY ((char *) __thread_pointer () + __rseq_offset ++ == (char *) &pd->rseq_area); ++ TEST_COMPARE (__rseq_size, 0); + TEST_COMPARE ((int) pd->rseq_area.cpu_id, RSEQ_CPU_ID_REGISTRATION_FAILED); + + int ret = syscall (__NR_rseq, &pd->rseq_area, sizeof (pd->rseq_area), +diff --git a/sysdeps/unix/sysv/linux/tst-rseq.c b/sysdeps/unix/sysv/linux/tst-rseq.c +index 926376b6..572c1116 100644 +--- a/sysdeps/unix/sysv/linux/tst-rseq.c ++++ b/sysdeps/unix/sysv/linux/tst-rseq.c +@@ -29,12 +29,20 @@ + # include + # include + # include ++# include ++# include + # include "tst-rseq.h" + + static void + do_rseq_main_test (void) + { ++ struct pthread *pd = THREAD_SELF; ++ + TEST_VERIFY_EXIT (rseq_thread_registered ()); ++ TEST_COMPARE (__rseq_flags, 0); ++ TEST_VERIFY ((char *) __thread_pointer () + __rseq_offset ++ == (char *) &pd->rseq_area); ++ TEST_COMPARE (__rseq_size, sizeof (pd->rseq_area)); + } + + static void +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist b/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist +index afddaec5..ae622bdf 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist ++++ b/sysdeps/unix/sysv/linux/x86_64/64/ld.abilist +@@ -3,3 +3,6 @@ GLIBC_2.2.5 _dl_mcount F + GLIBC_2.2.5 _r_debug D 0x28 + GLIBC_2.3 __tls_get_addr F + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 +diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist +index defc488d..e17496d1 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist ++++ b/sysdeps/unix/sysv/linux/x86_64/x32/ld.abilist +@@ -3,3 +3,6 @@ GLIBC_2.16 __tls_get_addr F + GLIBC_2.16 _dl_mcount F + GLIBC_2.16 _r_debug D 0x14 + GLIBC_2.34 __rtld_version_placeholder F ++GLIBC_2.35 __rseq_flags D 0x4 ++GLIBC_2.35 __rseq_offset D 0x4 ++GLIBC_2.35 __rseq_size D 0x4 +-- +2.23.0 + diff --git a/rseq-nptl-Add-rseq-registration.patch b/rseq-nptl-Add-rseq-registration.patch new file mode 100644 index 0000000000000000000000000000000000000000..1f76ab3519c7c7975da1d9c4b3f958bc31dc348d --- /dev/null +++ b/rseq-nptl-Add-rseq-registration.patch @@ -0,0 +1,1165 @@ +From 9394ca7ec895e284fcb7f5d7839feeb517acc249 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 21 Jan 2022 22:23:58 -0500 +Subject: [PATCH 4/9] nptl: Add rseq registration + +The rseq area is placed directly into struct pthread. rseq +registration failure is not treated as an error, so it is possible +that threads run with inconsistent registration status. + + is not yet installed as a public header. + +Co-Authored-By: Mathieu Desnoyers +Reviewed-by: Szabolcs Nagy +Reviewed-by: Siddhesh Poyarekar +------ +conflicts: + context conflict +--- + nptl/descr.h | 4 + + nptl/pthread_create.c | 13 + + sysdeps/nptl/dl-tls_init_tp.c | 8 +- + sysdeps/unix/sysv/linux/Makefile | 9 +- + sysdeps/unix/sysv/linux/aarch64/bits/rseq.h | 43 ++++ + sysdeps/unix/sysv/linux/arm/bits/rseq.h | 83 +++++++ + sysdeps/unix/sysv/linux/bits/rseq.h | 29 +++ + sysdeps/unix/sysv/linux/mips/bits/rseq.h | 62 +++++ + sysdeps/unix/sysv/linux/powerpc/bits/rseq.h | 37 +++ + sysdeps/unix/sysv/linux/rseq-internal.h | 45 ++++ + sysdeps/unix/sysv/linux/s390/bits/rseq.h | 37 +++ + sysdeps/unix/sysv/linux/sys/rseq.h | 174 +++++++++++++ + sysdeps/unix/sysv/linux/tst-rseq-nptl.c | 260 ++++++++++++++++++++ + sysdeps/unix/sysv/linux/tst-rseq.c | 64 +++++ + sysdeps/unix/sysv/linux/tst-rseq.h | 57 +++++ + sysdeps/unix/sysv/linux/x86/bits/rseq.h | 30 +++ + 16 files changed, 952 insertions(+), 3 deletions(-) + create mode 100644 sysdeps/unix/sysv/linux/aarch64/bits/rseq.h + create mode 100644 sysdeps/unix/sysv/linux/arm/bits/rseq.h + create mode 100644 sysdeps/unix/sysv/linux/bits/rseq.h + create mode 100644 sysdeps/unix/sysv/linux/mips/bits/rseq.h + create mode 100644 sysdeps/unix/sysv/linux/powerpc/bits/rseq.h + create mode 100644 sysdeps/unix/sysv/linux/rseq-internal.h + create mode 100644 sysdeps/unix/sysv/linux/s390/bits/rseq.h + create mode 100644 sysdeps/unix/sysv/linux/sys/rseq.h + create mode 100644 sysdeps/unix/sysv/linux/tst-rseq-nptl.c + create mode 100644 sysdeps/unix/sysv/linux/tst-rseq.c + create mode 100644 sysdeps/unix/sysv/linux/tst-rseq.h + create mode 100644 sysdeps/unix/sysv/linux/x86/bits/rseq.h + +diff --git a/nptl/descr.h b/nptl/descr.h +index 4de84138..79362661 100644 +--- a/nptl/descr.h ++++ b/nptl/descr.h +@@ -35,6 +35,7 @@ + #include + #include + #include ++#include + + #ifndef TCB_ALIGNMENT + # define TCB_ALIGNMENT sizeof (double) +@@ -405,6 +406,9 @@ struct pthread + /* Used on strsignal. */ + struct tls_internal_t tls_state; + ++ /* rseq area registered with the kernel. */ ++ struct rseq rseq_area; ++ + /* This member must be last. */ + char end_padding[]; + +diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c +index 3db0c9fd..d2b40924 100644 +--- a/nptl/pthread_create.c ++++ b/nptl/pthread_create.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + #include "libioP.h" + #include + #include +@@ -367,6 +368,9 @@ start_thread (void *arg) + /* Initialize pointers to locale data. */ + __ctype_init (); + ++ /* Register rseq TLS to the kernel. */ ++ rseq_register_current_thread (pd); ++ + #ifndef __ASSUME_SET_ROBUST_LIST + if (__nptl_set_robust_list_avail) + #endif +@@ -572,6 +576,15 @@ out: + process is really dead since 'clone' got passed the CLONE_CHILD_CLEARTID + flag. The 'tid' field in the TCB will be set to zero. + ++ rseq TLS is still registered at this point. Rely on implicit ++ unregistration performed by the kernel on thread teardown. This is not a ++ problem because the rseq TLS lives on the stack, and the stack outlives ++ the thread. If TCB allocation is ever changed, additional steps may be ++ required, such as performing explicit rseq unregistration before ++ reclaiming the rseq TLS area memory. It is NOT sufficient to block ++ signals because the kernel may write to the rseq area even without ++ signals. ++ + The exit code is zero since in case all threads exit by calling + 'pthread_exit' the exit status must be 0 (zero). */ + while (1) +diff --git a/sysdeps/nptl/dl-tls_init_tp.c b/sysdeps/nptl/dl-tls_init_tp.c +index ca494dd3..fedb876f 100644 +--- a/sysdeps/nptl/dl-tls_init_tp.c ++++ b/sysdeps/nptl/dl-tls_init_tp.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + + #ifndef __ASSUME_SET_ROBUST_LIST + bool __nptl_set_robust_list_avail; +@@ -57,11 +58,12 @@ __tls_pre_init_tp (void) + void + __tls_init_tp (void) + { ++ struct pthread *pd = THREAD_SELF; ++ + /* Set up thread stack list management. */ +- list_add (&THREAD_SELF->list, &GL (dl_stack_user)); ++ list_add (&pd->list, &GL (dl_stack_user)); + + /* Early initialization of the TCB. */ +- struct pthread *pd = THREAD_SELF; + pd->tid = INTERNAL_SYSCALL_CALL (set_tid_address, &pd->tid); + THREAD_SETMEM (pd, specific[0], &pd->specific_1stblock[0]); + THREAD_SETMEM (pd, user_stack, true); +@@ -90,6 +92,8 @@ __tls_init_tp (void) + } + } + ++ rseq_register_current_thread (pd); ++ + /* Set initial thread's stack block from 0 up to __libc_stack_end. + It will be bigger than it actually is, but for unwind.c/pt-longjmp.c + purposes this is good enough. */ +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index c3477480..f103a964 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -130,7 +130,10 @@ ifeq ($(have-GLIBC_2.27)$(build-shared),yesyes) + tests += tst-ofdlocks-compat + endif + +-tests-internal += tst-sigcontext-get_pc ++tests-internal += \ ++ tst-rseq \ ++ tst-sigcontext-get_pc \ ++ # tests-internal + + tests-time64 += \ + tst-adjtimex-time64 \ +@@ -370,4 +373,8 @@ endif + + ifeq ($(subdir),nptl) + tests += tst-align-clone tst-getpid1 ++ ++# tst-rseq-nptl is an internal test because it requires a definition of ++# __NR_rseq from the internal system call list. ++tests-internal += tst-rseq-nptl + endif +diff --git a/sysdeps/unix/sysv/linux/aarch64/bits/rseq.h b/sysdeps/unix/sysv/linux/aarch64/bits/rseq.h +new file mode 100644 +index 00000000..9ba92725 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/aarch64/bits/rseq.h +@@ -0,0 +1,43 @@ ++/* Restartable Sequences Linux aarch64 architecture header. ++ Copyright (C) 2021 Free Software Foundation, Inc. ++ ++ 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 ++ . */ ++ ++#ifndef _SYS_RSEQ_H ++# error "Never use directly; include instead." ++#endif ++ ++/* RSEQ_SIG is a signature required before each abort handler code. ++ ++ It is a 32-bit value that maps to actual architecture code compiled ++ into applications and libraries. It needs to be defined for each ++ architecture. When choosing this value, it needs to be taken into ++ account that generating invalid instructions may have ill effects on ++ tools like objdump, and may also have impact on the CPU speculative ++ execution efficiency in some cases. ++ ++ aarch64 -mbig-endian generates mixed endianness code vs data: ++ little-endian code and big-endian data. Ensure the RSEQ_SIG signature ++ matches code endianness. */ ++ ++#define RSEQ_SIG_CODE 0xd428bc00 /* BRK #0x45E0. */ ++ ++#ifdef __AARCH64EB__ ++# define RSEQ_SIG_DATA 0x00bc28d4 /* BRK #0x45E0. */ ++#else ++# define RSEQ_SIG_DATA RSEQ_SIG_CODE ++#endif ++ ++#define RSEQ_SIG RSEQ_SIG_DATA +diff --git a/sysdeps/unix/sysv/linux/arm/bits/rseq.h b/sysdeps/unix/sysv/linux/arm/bits/rseq.h +new file mode 100644 +index 00000000..0542b26f +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/arm/bits/rseq.h +@@ -0,0 +1,83 @@ ++/* Restartable Sequences Linux arm architecture header. ++ Copyright (C) 2021 Free Software Foundation, Inc. ++ ++ 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 ++ . */ ++ ++#ifndef _SYS_RSEQ_H ++# error "Never use directly; include instead." ++#endif ++ ++/* ++ RSEQ_SIG is a signature required before each abort handler code. ++ ++ It is a 32-bit value that maps to actual architecture code compiled ++ into applications and libraries. It needs to be defined for each ++ architecture. When choosing this value, it needs to be taken into ++ account that generating invalid instructions may have ill effects on ++ tools like objdump, and may also have impact on the CPU speculative ++ execution efficiency in some cases. ++ ++ - ARM little endian ++ ++ RSEQ_SIG uses the udf A32 instruction with an uncommon immediate operand ++ value 0x5de3. This traps if user-space reaches this instruction by mistake, ++ and the uncommon operand ensures the kernel does not move the instruction ++ pointer to attacker-controlled code on rseq abort. ++ ++ The instruction pattern in the A32 instruction set is: ++ ++ e7f5def3 udf #24035 ; 0x5de3 ++ ++ This translates to the following instruction pattern in the T16 instruction ++ set: ++ ++ little endian: ++ def3 udf #243 ; 0xf3 ++ e7f5 b.n <7f5> ++ ++ - ARMv6+ big endian (BE8): ++ ++ ARMv6+ -mbig-endian generates mixed endianness code vs data: little-endian ++ code and big-endian data. The data value of the signature needs to have its ++ byte order reversed to generate the trap instruction: ++ ++ Data: 0xf3def5e7 ++ ++ Translates to this A32 instruction pattern: ++ ++ e7f5def3 udf #24035 ; 0x5de3 ++ ++ Translates to this T16 instruction pattern: ++ ++ def3 udf #243 ; 0xf3 ++ e7f5 b.n <7f5> ++ ++ - Prior to ARMv6 big endian (BE32): ++ ++ Prior to ARMv6, -mbig-endian generates big-endian code and data ++ (which match), so the endianness of the data representation of the ++ signature should not be reversed. However, the choice between BE32 ++ and BE8 is done by the linker, so we cannot know whether code and ++ data endianness will be mixed before the linker is invoked. So rather ++ than try to play tricks with the linker, the rseq signature is simply ++ data (not a trap instruction) prior to ARMv6 on big endian. This is ++ why the signature is expressed as data (.word) rather than as ++ instruction (.inst) in assembler. */ ++ ++#ifdef __ARMEB__ ++# define RSEQ_SIG 0xf3def5e7 /* udf #24035 ; 0x5de3 (ARMv6+) */ ++#else ++# define RSEQ_SIG 0xe7f5def3 /* udf #24035 ; 0x5de3 */ ++#endif +diff --git a/sysdeps/unix/sysv/linux/bits/rseq.h b/sysdeps/unix/sysv/linux/bits/rseq.h +new file mode 100644 +index 00000000..46cf5d1c +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/bits/rseq.h +@@ -0,0 +1,29 @@ ++/* Restartable Sequences architecture header. Stub version. ++ Copyright (C) 2021 Free Software Foundation, Inc. ++ ++ 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 ++ . */ ++ ++#ifndef _SYS_RSEQ_H ++# error "Never use directly; include instead." ++#endif ++ ++/* RSEQ_SIG is a signature required before each abort handler code. ++ ++ It is a 32-bit value that maps to actual architecture code compiled ++ into applications and libraries. It needs to be defined for each ++ architecture. When choosing this value, it needs to be taken into ++ account that generating invalid instructions may have ill effects on ++ tools like objdump, and may also have impact on the CPU speculative ++ execution efficiency in some cases. */ +diff --git a/sysdeps/unix/sysv/linux/mips/bits/rseq.h b/sysdeps/unix/sysv/linux/mips/bits/rseq.h +new file mode 100644 +index 00000000..a9defee5 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/mips/bits/rseq.h +@@ -0,0 +1,62 @@ ++/* Restartable Sequences Linux mips architecture header. ++ Copyright (C) 2021 Free Software Foundation, Inc. ++ ++ 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 ++ . */ ++ ++#ifndef _SYS_RSEQ_H ++# error "Never use directly; include instead." ++#endif ++ ++/* RSEQ_SIG is a signature required before each abort handler code. ++ ++ It is a 32-bit value that maps to actual architecture code compiled ++ into applications and libraries. It needs to be defined for each ++ architecture. When choosing this value, it needs to be taken into ++ account that generating invalid instructions may have ill effects on ++ tools like objdump, and may also have impact on the CPU speculative ++ execution efficiency in some cases. ++ ++ RSEQ_SIG uses the break instruction. The instruction pattern is: ++ ++ On MIPS: ++ 0350000d break 0x350 ++ ++ On nanoMIPS: ++ 00100350 break 0x350 ++ ++ On microMIPS: ++ 0000d407 break 0x350 ++ ++ For nanoMIPS32 and microMIPS, the instruction stream is encoded as ++ 16-bit halfwords, so the signature halfwords need to be swapped ++ accordingly for little-endian. */ ++ ++#if defined (__nanomips__) ++# ifdef __MIPSEL__ ++# define RSEQ_SIG 0x03500010 ++# else ++# define RSEQ_SIG 0x00100350 ++# endif ++#elif defined (__mips_micromips) ++# ifdef __MIPSEL__ ++# define RSEQ_SIG 0xd4070000 ++# else ++# define RSEQ_SIG 0x0000d407 ++# endif ++#elif defined (__mips__) ++# define RSEQ_SIG 0x0350000d ++#else ++/* Unknown MIPS architecture. */ ++#endif +diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/rseq.h b/sysdeps/unix/sysv/linux/powerpc/bits/rseq.h +new file mode 100644 +index 00000000..05b3cf7b +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/powerpc/bits/rseq.h +@@ -0,0 +1,37 @@ ++/* Restartable Sequences Linux powerpc architecture header. ++ Copyright (C) 2021 Free Software Foundation, Inc. ++ ++ 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 ++ . */ ++ ++#ifndef _SYS_RSEQ_H ++# error "Never use directly; include instead." ++#endif ++ ++/* RSEQ_SIG is a signature required before each abort handler code. ++ ++ It is a 32-bit value that maps to actual architecture code compiled ++ into applications and libraries. It needs to be defined for each ++ architecture. When choosing this value, it needs to be taken into ++ account that generating invalid instructions may have ill effects on ++ tools like objdump, and may also have impact on the CPU speculative ++ execution efficiency in some cases. ++ ++ RSEQ_SIG uses the following trap instruction: ++ ++ powerpc-be: 0f e5 00 0b twui r5,11 ++ powerpc64-le: 0b 00 e5 0f twui r5,11 ++ powerpc64-be: 0f e5 00 0b twui r5,11 */ ++ ++#define RSEQ_SIG 0x0fe5000b +diff --git a/sysdeps/unix/sysv/linux/rseq-internal.h b/sysdeps/unix/sysv/linux/rseq-internal.h +new file mode 100644 +index 00000000..909f5478 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/rseq-internal.h +@@ -0,0 +1,45 @@ ++/* Restartable Sequences internal API. Linux implementation. ++ Copyright (C) 2021 Free Software Foundation, Inc. ++ ++ 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 ++ . */ ++ ++#ifndef RSEQ_INTERNAL_H ++#define RSEQ_INTERNAL_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef RSEQ_SIG ++static inline void ++rseq_register_current_thread (struct pthread *self) ++{ ++ int ret = INTERNAL_SYSCALL_CALL (rseq, ++ &self->rseq_area, sizeof (self->rseq_area), ++ 0, RSEQ_SIG); ++ if (INTERNAL_SYSCALL_ERROR_P (ret)) ++ THREAD_SETMEM (self, rseq_area.cpu_id, RSEQ_CPU_ID_REGISTRATION_FAILED); ++} ++#else /* RSEQ_SIG */ ++static inline void ++rseq_register_current_thread (struct pthread *self) ++{ ++ THREAD_SETMEM (self, rseq_area.cpu_id, RSEQ_CPU_ID_REGISTRATION_FAILED); ++} ++#endif /* RSEQ_SIG */ ++ ++#endif /* rseq-internal.h */ +diff --git a/sysdeps/unix/sysv/linux/s390/bits/rseq.h b/sysdeps/unix/sysv/linux/s390/bits/rseq.h +new file mode 100644 +index 00000000..3030e38f +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/s390/bits/rseq.h +@@ -0,0 +1,37 @@ ++/* Restartable Sequences Linux s390 architecture header. ++ Copyright (C) 2021 Free Software Foundation, Inc. ++ ++ 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 ++ . */ ++ ++#ifndef _SYS_RSEQ_H ++# error "Never use directly; include instead." ++#endif ++ ++/* RSEQ_SIG is a signature required before each abort handler code. ++ ++ It is a 32-bit value that maps to actual architecture code compiled ++ into applications and libraries. It needs to be defined for each ++ architecture. When choosing this value, it needs to be taken into ++ account that generating invalid instructions may have ill effects on ++ tools like objdump, and may also have impact on the CPU speculative ++ execution efficiency in some cases. ++ ++ RSEQ_SIG uses the trap4 instruction. As Linux does not make use of the ++ access-register mode nor the linkage stack this instruction will always ++ cause a special-operation exception (the trap-enabled bit in the DUCT ++ is and will stay 0). The instruction pattern is ++ b2 ff 0f ff trap4 4095(%r0) */ ++ ++#define RSEQ_SIG 0xB2FF0FFF +diff --git a/sysdeps/unix/sysv/linux/sys/rseq.h b/sysdeps/unix/sysv/linux/sys/rseq.h +new file mode 100644 +index 00000000..c8edff50 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/sys/rseq.h +@@ -0,0 +1,174 @@ ++/* Restartable Sequences exported symbols. Linux header. ++ Copyright (C) 2021 Free Software Foundation, Inc. ++ ++ 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 ++ . */ ++ ++#ifndef _SYS_RSEQ_H ++#define _SYS_RSEQ_H 1 ++ ++/* Architecture-specific rseq signature. */ ++#include ++ ++#include ++#include ++#include ++ ++#ifdef __has_include ++# if __has_include ("linux/rseq.h") ++# define __GLIBC_HAVE_KERNEL_RSEQ ++# endif ++#else ++# include ++# if LINUX_VERSION_CODE >= KERNEL_VERSION (4, 18, 0) ++# define __GLIBC_HAVE_KERNEL_RSEQ ++# endif ++#endif ++ ++#ifdef __GLIBC_HAVE_KERNEL_RSEQ ++/* We use the structures declarations from the kernel headers. */ ++# include ++#else /* __GLIBC_HAVE_KERNEL_RSEQ */ ++/* We use a copy of the include/uapi/linux/rseq.h kernel header. */ ++ ++enum rseq_cpu_id_state ++ { ++ RSEQ_CPU_ID_UNINITIALIZED = -1, ++ RSEQ_CPU_ID_REGISTRATION_FAILED = -2, ++ }; ++ ++enum rseq_flags ++ { ++ RSEQ_FLAG_UNREGISTER = (1 << 0), ++ }; ++ ++enum rseq_cs_flags_bit ++ { ++ RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT_BIT = 0, ++ RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL_BIT = 1, ++ RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE_BIT = 2, ++ }; ++ ++enum rseq_cs_flags ++ { ++ RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT = ++ (1U << RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT_BIT), ++ RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL = ++ (1U << RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL_BIT), ++ RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE = ++ (1U << RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE_BIT), ++ }; ++ ++/* struct rseq_cs is aligned on 32 bytes to ensure it is always ++ contained within a single cache-line. It is usually declared as ++ link-time constant data. */ ++struct rseq_cs ++ { ++ /* Version of this structure. */ ++ uint32_t version; ++ /* enum rseq_cs_flags. */ ++ uint32_t flags; ++ uint64_t start_ip; ++ /* Offset from start_ip. */ ++ uint64_t post_commit_offset; ++ uint64_t abort_ip; ++ } __attribute__ ((__aligned__ (32))); ++ ++/* struct rseq is aligned on 32 bytes to ensure it is always ++ contained within a single cache-line. ++ ++ A single struct rseq per thread is allowed. */ ++struct rseq ++ { ++ /* Restartable sequences cpu_id_start field. Updated by the ++ kernel. Read by user-space with single-copy atomicity ++ semantics. This field should only be read by the thread which ++ registered this data structure. Aligned on 32-bit. Always ++ contains a value in the range of possible CPUs, although the ++ value may not be the actual current CPU (e.g. if rseq is not ++ initialized). This CPU number value should always be compared ++ against the value of the cpu_id field before performing a rseq ++ commit or returning a value read from a data structure indexed ++ using the cpu_id_start value. */ ++ uint32_t cpu_id_start; ++ /* Restartable sequences cpu_id field. Updated by the kernel. ++ Read by user-space with single-copy atomicity semantics. This ++ field should only be read by the thread which registered this ++ data structure. Aligned on 32-bit. Values ++ RSEQ_CPU_ID_UNINITIALIZED and RSEQ_CPU_ID_REGISTRATION_FAILED ++ have a special semantic: the former means "rseq uninitialized", ++ and latter means "rseq initialization failed". This value is ++ meant to be read within rseq critical sections and compared ++ with the cpu_id_start value previously read, before performing ++ the commit instruction, or read and compared with the ++ cpu_id_start value before returning a value loaded from a data ++ structure indexed using the cpu_id_start value. */ ++ uint32_t cpu_id; ++ /* Restartable sequences rseq_cs field. ++ ++ Contains NULL when no critical section is active for the current ++ thread, or holds a pointer to the currently active struct rseq_cs. ++ ++ Updated by user-space, which sets the address of the currently ++ active rseq_cs at the beginning of assembly instruction sequence ++ block, and set to NULL by the kernel when it restarts an assembly ++ instruction sequence block, as well as when the kernel detects that ++ it is preempting or delivering a signal outside of the range ++ targeted by the rseq_cs. Also needs to be set to NULL by user-space ++ before reclaiming memory that contains the targeted struct rseq_cs. ++ ++ Read and set by the kernel. Set by user-space with single-copy ++ atomicity semantics. This field should only be updated by the ++ thread which registered this data structure. Aligned on 64-bit. */ ++ union ++ { ++ uint64_t ptr64; ++# ifdef __LP64__ ++ uint64_t ptr; ++# else /* __LP64__ */ ++ struct ++ { ++#if __BYTE_ORDER == __BIG_ENDIAN ++ uint32_t padding; /* Initialized to zero. */ ++ uint32_t ptr32; ++# else /* LITTLE */ ++ uint32_t ptr32; ++ uint32_t padding; /* Initialized to zero. */ ++# endif /* ENDIAN */ ++ } ptr; ++# endif /* __LP64__ */ ++ } rseq_cs; ++ ++ /* Restartable sequences flags field. ++ ++ This field should only be updated by the thread which ++ registered this data structure. Read by the kernel. ++ Mainly used for single-stepping through rseq critical sections ++ with debuggers. ++ ++ - RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT ++ Inhibit instruction sequence block restart on preemption ++ for this thread. ++ - RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL ++ Inhibit instruction sequence block restart on signal ++ delivery for this thread. ++ - RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE ++ Inhibit instruction sequence block restart on migration for ++ this thread. */ ++ uint32_t flags; ++ } __attribute__ ((__aligned__ (32))); ++ ++#endif /* __GLIBC_HAVE_KERNEL_RSEQ */ ++ ++#endif /* sys/rseq.h */ +diff --git a/sysdeps/unix/sysv/linux/tst-rseq-nptl.c b/sysdeps/unix/sysv/linux/tst-rseq-nptl.c +new file mode 100644 +index 00000000..d31d9444 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-rseq-nptl.c +@@ -0,0 +1,260 @@ ++/* Restartable Sequences NPTL test. ++ Copyright (C) 2021 Free Software Foundation, Inc. ++ ++ 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 ++ . */ ++ ++/* These tests validate that rseq is registered from various execution ++ contexts (main thread, destructor, other threads, other threads created ++ from destructor, forked process (without exec), pthread_atfork handlers, ++ pthread setspecific destructors, signal handlers, atexit handlers). ++ ++ See the Linux kernel selftests for extensive rseq stress-tests. */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef RSEQ_SIG ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include "tst-rseq.h" ++ ++static pthread_key_t rseq_test_key; ++ ++static void ++atfork_prepare (void) ++{ ++ if (!rseq_thread_registered ()) ++ { ++ printf ("error: rseq not registered in pthread atfork prepare\n"); ++ support_record_failure (); ++ } ++} ++ ++static void ++atfork_parent (void) ++{ ++ if (!rseq_thread_registered ()) ++ { ++ printf ("error: rseq not registered in pthread atfork parent\n"); ++ support_record_failure (); ++ } ++} ++ ++static void ++atfork_child (void) ++{ ++ if (!rseq_thread_registered ()) ++ { ++ printf ("error: rseq not registered in pthread atfork child\n"); ++ support_record_failure (); ++ } ++} ++ ++static void ++rseq_key_destructor (void *arg) ++{ ++ /* Cannot use deferred failure reporting after main returns. */ ++ if (!rseq_thread_registered ()) ++ FAIL_EXIT1 ("rseq not registered in pthread key destructor"); ++} ++ ++static void ++atexit_handler (void) ++{ ++ /* Cannot use deferred failure reporting after main returns. */ ++ if (!rseq_thread_registered ()) ++ FAIL_EXIT1 ("rseq not registered in atexit handler"); ++} ++ ++/* Used to avoid -Werror=stringop-overread warning with ++ pthread_setspecific and GCC 11. */ ++static char one = 1; ++ ++static void ++do_rseq_main_test (void) ++{ ++ TEST_COMPARE (atexit (atexit_handler), 0); ++ rseq_test_key = xpthread_key_create (rseq_key_destructor); ++ TEST_COMPARE (pthread_atfork (atfork_prepare, atfork_parent, atfork_child), 0); ++ xraise (SIGUSR1); ++ TEST_COMPARE (pthread_setspecific (rseq_test_key, &one), 0); ++ TEST_VERIFY_EXIT (rseq_thread_registered ()); ++} ++ ++static void ++cancel_routine (void *arg) ++{ ++ if (!rseq_thread_registered ()) ++ { ++ printf ("error: rseq not registered in cancel routine\n"); ++ support_record_failure (); ++ } ++} ++ ++static pthread_barrier_t cancel_thread_barrier; ++static pthread_cond_t cancel_thread_cond = PTHREAD_COND_INITIALIZER; ++static pthread_mutex_t cancel_thread_mutex = PTHREAD_MUTEX_INITIALIZER; ++ ++static void ++test_cancel_thread (void) ++{ ++ pthread_cleanup_push (cancel_routine, NULL); ++ (void) xpthread_barrier_wait (&cancel_thread_barrier); ++ /* Wait forever until cancellation. */ ++ xpthread_cond_wait (&cancel_thread_cond, &cancel_thread_mutex); ++ pthread_cleanup_pop (0); ++} ++ ++static void * ++thread_function (void * arg) ++{ ++ int i = (int) (intptr_t) arg; ++ ++ xraise (SIGUSR1); ++ if (i == 0) ++ test_cancel_thread (); ++ TEST_COMPARE (pthread_setspecific (rseq_test_key, &one), 0); ++ return rseq_thread_registered () ? NULL : (void *) 1l; ++} ++ ++static void ++sighandler (int sig) ++{ ++ if (!rseq_thread_registered ()) ++ { ++ printf ("error: rseq not registered in signal handler\n"); ++ support_record_failure (); ++ } ++} ++ ++static void ++setup_signals (void) ++{ ++ struct sigaction sa; ++ ++ sigemptyset (&sa.sa_mask); ++ sigaddset (&sa.sa_mask, SIGUSR1); ++ sa.sa_flags = 0; ++ sa.sa_handler = sighandler; ++ xsigaction (SIGUSR1, &sa, NULL); ++} ++ ++static int ++do_rseq_threads_test (int nr_threads) ++{ ++ pthread_t th[nr_threads]; ++ int i; ++ int result = 0; ++ ++ xpthread_barrier_init (&cancel_thread_barrier, NULL, 2); ++ ++ for (i = 0; i < nr_threads; ++i) ++ th[i] = xpthread_create (NULL, thread_function, ++ (void *) (intptr_t) i); ++ ++ (void) xpthread_barrier_wait (&cancel_thread_barrier); ++ ++ xpthread_cancel (th[0]); ++ ++ for (i = 0; i < nr_threads; ++i) ++ { ++ void *v; ++ ++ v = xpthread_join (th[i]); ++ if (i != 0 && v != NULL) ++ { ++ printf ("error: join %d successful, but child failed\n", i); ++ result = 1; ++ } ++ else if (i == 0 && v == NULL) ++ { ++ printf ("error: join %d successful, child did not fail as expected\n", i); ++ result = 1; ++ } ++ } ++ ++ xpthread_barrier_destroy (&cancel_thread_barrier); ++ ++ return result; ++} ++ ++static void ++subprocess_callback (void *closure) ++{ ++ do_rseq_main_test (); ++} ++ ++static void ++do_rseq_fork_test (void) ++{ ++ support_isolate_in_subprocess (subprocess_callback, NULL); ++} ++ ++static int ++do_rseq_test (void) ++{ ++ int t[] = { 1, 2, 6, 5, 4, 3, 50 }; ++ int i, result = 0; ++ ++ if (!rseq_available ()) ++ FAIL_UNSUPPORTED ("kernel does not support rseq, skipping test"); ++ setup_signals (); ++ xraise (SIGUSR1); ++ do_rseq_main_test (); ++ for (i = 0; i < array_length (t); i++) ++ if (do_rseq_threads_test (t[i])) ++ result = 1; ++ do_rseq_fork_test (); ++ return result; ++} ++ ++static void __attribute__ ((destructor)) ++do_rseq_destructor_test (void) ++{ ++ /* Cannot use deferred failure reporting after main returns. */ ++ if (do_rseq_test ()) ++ FAIL_EXIT1 ("rseq not registered within destructor"); ++ xpthread_key_delete (rseq_test_key); ++} ++ ++#else /* RSEQ_SIG */ ++static int ++do_rseq_test (void) ++{ ++ FAIL_UNSUPPORTED ("glibc does not define RSEQ_SIG, skipping test"); ++ return 0; ++} ++#endif /* RSEQ_SIG */ ++ ++static int ++do_test (void) ++{ ++ return do_rseq_test (); ++} ++ ++#include +diff --git a/sysdeps/unix/sysv/linux/tst-rseq.c b/sysdeps/unix/sysv/linux/tst-rseq.c +new file mode 100644 +index 00000000..926376b6 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-rseq.c +@@ -0,0 +1,64 @@ ++/* Restartable Sequences single-threaded tests. ++ Copyright (C) 2021 Free Software Foundation, Inc. ++ ++ 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 ++ . */ ++ ++/* These tests validate that rseq is registered from main in an executable ++ not linked against libpthread. */ ++ ++#include ++#include ++#include ++#include ++ ++#ifdef RSEQ_SIG ++# include ++# include ++# include ++# include ++# include ++# include "tst-rseq.h" ++ ++static void ++do_rseq_main_test (void) ++{ ++ TEST_VERIFY_EXIT (rseq_thread_registered ()); ++} ++ ++static void ++do_rseq_test (void) ++{ ++ if (!rseq_available ()) ++ { ++ FAIL_UNSUPPORTED ("kernel does not support rseq, skipping test"); ++ } ++ do_rseq_main_test (); ++} ++#else /* RSEQ_SIG */ ++static void ++do_rseq_test (void) ++{ ++ FAIL_UNSUPPORTED ("glibc does not define RSEQ_SIG, skipping test"); ++} ++#endif /* RSEQ_SIG */ ++ ++static int ++do_test (void) ++{ ++ do_rseq_test (); ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/unix/sysv/linux/tst-rseq.h b/sysdeps/unix/sysv/linux/tst-rseq.h +new file mode 100644 +index 00000000..a476c316 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-rseq.h +@@ -0,0 +1,57 @@ ++/* Restartable Sequences tests header. ++ Copyright (C) 2021 Free Software Foundation, Inc. ++ ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static inline bool ++rseq_thread_registered (void) ++{ ++ return THREAD_GETMEM_VOLATILE (THREAD_SELF, rseq_area.cpu_id) >= 0; ++} ++ ++static inline int ++sys_rseq (struct rseq *rseq_abi, uint32_t rseq_len, int flags, uint32_t sig) ++{ ++ return syscall (__NR_rseq, rseq_abi, rseq_len, flags, sig); ++} ++ ++static inline bool ++rseq_available (void) ++{ ++ int rc; ++ ++ rc = sys_rseq (NULL, 0, 0, 0); ++ if (rc != -1) ++ FAIL_EXIT1 ("Unexpected rseq return value %d", rc); ++ switch (errno) ++ { ++ case ENOSYS: ++ return false; ++ case EINVAL: ++ /* rseq is implemented, but detected an invalid rseq_len parameter. */ ++ return true; ++ default: ++ FAIL_EXIT1 ("Unexpected rseq error %s", strerror (errno)); ++ } ++} +diff --git a/sysdeps/unix/sysv/linux/x86/bits/rseq.h b/sysdeps/unix/sysv/linux/x86/bits/rseq.h +new file mode 100644 +index 00000000..9fc909e7 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/x86/bits/rseq.h +@@ -0,0 +1,30 @@ ++/* Restartable Sequences Linux x86 architecture header. ++ Copyright (C) 2021 Free Software Foundation, Inc. ++ ++ 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 ++ . */ ++ ++#ifndef _SYS_RSEQ_H ++# error "Never use directly; include instead." ++#endif ++ ++/* RSEQ_SIG is a signature required before each abort handler code. ++ ++ RSEQ_SIG is used with the following reserved undefined instructions, which ++ trap in user-space: ++ ++ x86-32: 0f b9 3d 53 30 05 53 ud1 0x53053053,%edi ++ x86-64: 0f b9 3d 53 30 05 53 ud1 0x53053053(%rip),%edi */ ++ ++#define RSEQ_SIG 0x53053053 +-- +2.23.0 + diff --git a/rseq-nptl-Add-thread_pointer.h-for-defining-__thread_poin.patch b/rseq-nptl-Add-thread_pointer.h-for-defining-__thread_poin.patch new file mode 100644 index 0000000000000000000000000000000000000000..39c25a0cb521f8d5231e7d584549219b3f66a574 --- /dev/null +++ b/rseq-nptl-Add-thread_pointer.h-for-defining-__thread_poin.patch @@ -0,0 +1,141 @@ +From c773e8d7fb0c7a97290bd889ba984411a1952e9e Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Thu, 9 Dec 2021 09:49:32 +0100 +Subject: [PATCH 1/9] nptl: Add for defining + __thread_pointer + + already contains a definition that is quite similar, +but it is not consistent across architectures. + +Only architectures for which rseq support is added are covered. + +Reviewed-by: Szabolcs Nagy +--- + sysdeps/nptl/thread_pointer.h | 28 ++++++++++++++++++++ + sysdeps/powerpc/nptl/thread_pointer.h | 33 +++++++++++++++++++++++ + sysdeps/x86/nptl/thread_pointer.h | 38 +++++++++++++++++++++++++++ + 3 files changed, 99 insertions(+) + create mode 100644 sysdeps/nptl/thread_pointer.h + create mode 100644 sysdeps/powerpc/nptl/thread_pointer.h + create mode 100644 sysdeps/x86/nptl/thread_pointer.h + +diff --git a/sysdeps/nptl/thread_pointer.h b/sysdeps/nptl/thread_pointer.h +new file mode 100644 +index 00000000..92f2f309 +--- /dev/null ++++ b/sysdeps/nptl/thread_pointer.h +@@ -0,0 +1,28 @@ ++/* __thread_pointer definition. Generic version. ++ 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 ++ . */ ++ ++#ifndef _SYS_THREAD_POINTER_H ++#define _SYS_THREAD_POINTER_H ++ ++static inline void * ++__thread_pointer (void) ++{ ++ return __builtin_thread_pointer (); ++} ++ ++#endif /* _SYS_THREAD_POINTER_H */ +diff --git a/sysdeps/powerpc/nptl/thread_pointer.h b/sysdeps/powerpc/nptl/thread_pointer.h +new file mode 100644 +index 00000000..8fd5ba67 +--- /dev/null ++++ b/sysdeps/powerpc/nptl/thread_pointer.h +@@ -0,0 +1,33 @@ ++/* __thread_pointer definition. powerpc version. ++ 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 ++ . */ ++ ++#ifndef _SYS_THREAD_POINTER_H ++#define _SYS_THREAD_POINTER_H ++ ++static inline void * ++__thread_pointer (void) ++{ ++#ifdef __powerpc64__ ++ register void *__result asm ("r13"); ++#else ++ register void *__result asm ("r2"); ++#endif ++ return __result; ++} ++ ++#endif /* _SYS_THREAD_POINTER_H */ +diff --git a/sysdeps/x86/nptl/thread_pointer.h b/sysdeps/x86/nptl/thread_pointer.h +new file mode 100644 +index 00000000..6b71b6f7 +--- /dev/null ++++ b/sysdeps/x86/nptl/thread_pointer.h +@@ -0,0 +1,38 @@ ++/* __thread_pointer definition. x86 version. ++ 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 ++ . */ ++ ++#ifndef _SYS_THREAD_POINTER_H ++#define _SYS_THREAD_POINTER_H ++ ++static inline void * ++__thread_pointer (void) ++{ ++#if __GNUC_PREREQ (11, 1) ++ return __builtin_thread_pointer (); ++#else ++ void *__result; ++# ifdef __x86_64__ ++ __asm__ ("mov %%fs:0, %0" : "=r" (__result)); ++# else ++ __asm__ ("mov %%gs:0, %0" : "=r" (__result)); ++# endif ++ return __result; ++#endif /* !GCC 11 */ ++} ++ ++#endif /* _SYS_THREAD_POINTER_H */ +-- +2.23.0 + diff --git a/rseq-nptl-Introduce-THREAD_GETMEM_VOLATILE.patch b/rseq-nptl-Introduce-THREAD_GETMEM_VOLATILE.patch new file mode 100644 index 0000000000000000000000000000000000000000..4ad2329bbe80a32a6277a423e29b13149e17a834 --- /dev/null +++ b/rseq-nptl-Introduce-THREAD_GETMEM_VOLATILE.patch @@ -0,0 +1,56 @@ +From 6a8628eca8c8b22ccfd1422f2eb27bb665cfd660 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Thu, 9 Dec 2021 09:49:32 +0100 +Subject: [PATCH 3/9] nptl: Introduce THREAD_GETMEM_VOLATILE + +This will be needed for rseq TCB access. + +Reviewed-by: Szabolcs Nagy +--- + sysdeps/i386/nptl/tcb-access.h | 2 ++ + sysdeps/nptl/tcb-access.h | 2 ++ + sysdeps/x86_64/nptl/tcb-access.h | 2 ++ + 3 files changed, 6 insertions(+) + +diff --git a/sysdeps/i386/nptl/tcb-access.h b/sysdeps/i386/nptl/tcb-access.h +index 6c6d561e..5ddd8322 100644 +--- a/sysdeps/i386/nptl/tcb-access.h ++++ b/sysdeps/i386/nptl/tcb-access.h +@@ -41,6 +41,8 @@ + } \ + __value; }) + ++/* THREAD_GETMEM already forces a read. */ ++#define THREAD_GETMEM_VOLATILE(descr, member) THREAD_GETMEM (descr, member) + + /* Same as THREAD_GETMEM, but the member offset can be non-constant. */ + #define THREAD_GETMEM_NC(descr, member, idx) \ +diff --git a/sysdeps/nptl/tcb-access.h b/sysdeps/nptl/tcb-access.h +index b4137b8a..bbe20b72 100644 +--- a/sysdeps/nptl/tcb-access.h ++++ b/sysdeps/nptl/tcb-access.h +@@ -22,6 +22,8 @@ + + #define THREAD_GETMEM(descr, member) \ + descr->member ++#define THREAD_GETMEM_VOLATILE(descr, member) \ ++ (*(volatile __typeof (descr->member) *)&descr->member) + #define THREAD_GETMEM_NC(descr, member, idx) \ + descr->member[idx] + #define THREAD_SETMEM(descr, member, value) \ +diff --git a/sysdeps/x86_64/nptl/tcb-access.h b/sysdeps/x86_64/nptl/tcb-access.h +index 18848a72..e4d2d07a 100644 +--- a/sysdeps/x86_64/nptl/tcb-access.h ++++ b/sysdeps/x86_64/nptl/tcb-access.h +@@ -39,6 +39,8 @@ + } \ + __value; }) + ++/* THREAD_GETMEM already forces a read. */ ++#define THREAD_GETMEM_VOLATILE(descr, member) THREAD_GETMEM (descr, member) + + /* Same as THREAD_GETMEM, but the member offset can be non-constant. */ + # define THREAD_GETMEM_NC(descr, member, idx) \ +-- +2.23.0 + diff --git a/rseq-nptl-Introduce-tcb-access.h-for-THREAD_-accessors.patch b/rseq-nptl-Introduce-tcb-access.h-for-THREAD_-accessors.patch new file mode 100644 index 0000000000000000000000000000000000000000..0d5411925c775d3a29445240d50c70dbb33bc25a --- /dev/null +++ b/rseq-nptl-Introduce-tcb-access.h-for-THREAD_-accessors.patch @@ -0,0 +1,935 @@ +From da3869963c4039b583d011e5612c2546efe90ed3 Mon Sep 17 00:00:00 2001 +From: qinyu +Date: Fri, 25 Feb 2022 10:55:45 +0800 +Subject: [PATCH 2/9] nptl: Introduce for THREAD_* accessors + +These are common between most architectures. Only the x86 targets +are outliers. + +Reviewed-by: Szabolcs Nagy +------ +conflicts: + context conflicts +--- + sysdeps/aarch64/nptl/tls.h | 10 +-- + sysdeps/alpha/nptl/tls.h | 10 +-- + sysdeps/arc/nptl/tls.h | 10 +-- + sysdeps/arm/nptl/tls.h | 10 +-- + sysdeps/csky/nptl/tls.h | 10 +-- + sysdeps/hppa/nptl/tls.h | 10 +-- + sysdeps/i386/nptl/tcb-access.h | 123 +++++++++++++++++++++++++++++ + sysdeps/i386/nptl/tls.h | 108 +------------------------ + sysdeps/ia64/nptl/tls.h | 10 +-- + sysdeps/m68k/nptl/tls.h | 10 +-- + sysdeps/microblaze/nptl/tls.h | 15 +--- + sysdeps/mips/nptl/tls.h | 9 +-- + sysdeps/nios2/nptl/tls.h | 10 +-- + sysdeps/nptl/tcb-access.h | 30 +++++++ + sysdeps/powerpc/nptl/tls.h | 15 +--- + sysdeps/riscv/nptl/tls.h | 9 +-- + sysdeps/s390/nptl/tls.h | 10 +-- + sysdeps/sh/nptl/tls.h | 14 +--- + sysdeps/sparc/nptl/tls.h | 10 +-- + sysdeps/x86_64/nptl/tcb-access.h | 130 +++++++++++++++++++++++++++++++ + sysdeps/x86_64/nptl/tls.h | 114 +-------------------------- + 21 files changed, 301 insertions(+), 376 deletions(-) + create mode 100644 sysdeps/i386/nptl/tcb-access.h + create mode 100644 sysdeps/nptl/tcb-access.h + create mode 100644 sysdeps/x86_64/nptl/tcb-access.h + +diff --git a/sysdeps/aarch64/nptl/tls.h b/sysdeps/aarch64/nptl/tls.h +index 6e896207..cd9abb5d 100644 +--- a/sysdeps/aarch64/nptl/tls.h ++++ b/sysdeps/aarch64/nptl/tls.h +@@ -98,15 +98,7 @@ typedef struct + # define DB_THREAD_SELF \ + CONST_THREAD_AREA (64, sizeof (struct pthread)) + +-/* Access to data in the thread descriptor is easy. */ +-# define THREAD_GETMEM(descr, member) \ +- descr->member +-# define THREAD_GETMEM_NC(descr, member, idx) \ +- descr->member[idx] +-# define THREAD_SETMEM(descr, member, value) \ +- descr->member = (value) +-# define THREAD_SETMEM_NC(descr, member, idx, value) \ +- descr->member[idx] = (value) ++# include + + /* Get and set the global scope generation counter in struct pthread. */ + # define THREAD_GSCOPE_IN_TCB 1 +diff --git a/sysdeps/alpha/nptl/tls.h b/sysdeps/alpha/nptl/tls.h +index 4dbccc52..5f4843b2 100644 +--- a/sysdeps/alpha/nptl/tls.h ++++ b/sysdeps/alpha/nptl/tls.h +@@ -92,15 +92,7 @@ typedef struct + # define DB_THREAD_SELF \ + REGISTER (64, 64, 32 * 8, -sizeof (struct pthread)) + +-/* Access to data in the thread descriptor is easy. */ +-#define THREAD_GETMEM(descr, member) \ +- descr->member +-#define THREAD_GETMEM_NC(descr, member, idx) \ +- descr->member[idx] +-#define THREAD_SETMEM(descr, member, value) \ +- descr->member = (value) +-#define THREAD_SETMEM_NC(descr, member, idx, value) \ +- descr->member[idx] = (value) ++# include + + /* Get and set the global scope generation counter in struct pthread. */ + #define THREAD_GSCOPE_IN_TCB 1 +diff --git a/sysdeps/arc/nptl/tls.h b/sysdeps/arc/nptl/tls.h +index 95300fdd..d9ada2f3 100644 +--- a/sysdeps/arc/nptl/tls.h ++++ b/sysdeps/arc/nptl/tls.h +@@ -100,15 +100,7 @@ typedef struct + # define DB_THREAD_SELF \ + CONST_THREAD_AREA (32, sizeof (struct pthread)) + +-/* Access to data in the thread descriptor is easy. */ +-# define THREAD_GETMEM(descr, member) \ +- descr->member +-# define THREAD_GETMEM_NC(descr, member, idx) \ +- descr->member[idx] +-# define THREAD_SETMEM(descr, member, value) \ +- descr->member = (value) +-# define THREAD_SETMEM_NC(descr, member, idx, value) \ +- descr->member[idx] = (value) ++# include + + /* Get and set the global scope generation counter in struct pthread. */ + #define THREAD_GSCOPE_IN_TCB 1 +diff --git a/sysdeps/arm/nptl/tls.h b/sysdeps/arm/nptl/tls.h +index 1bd11307..354aae33 100644 +--- a/sysdeps/arm/nptl/tls.h ++++ b/sysdeps/arm/nptl/tls.h +@@ -89,15 +89,7 @@ typedef struct + # define DB_THREAD_SELF \ + CONST_THREAD_AREA (32, sizeof (struct pthread)) + +-/* Access to data in the thread descriptor is easy. */ +-#define THREAD_GETMEM(descr, member) \ +- descr->member +-#define THREAD_GETMEM_NC(descr, member, idx) \ +- descr->member[idx] +-#define THREAD_SETMEM(descr, member, value) \ +- descr->member = (value) +-#define THREAD_SETMEM_NC(descr, member, idx, value) \ +- descr->member[idx] = (value) ++# include + + /* Get and set the global scope generation counter in struct pthread. */ + #define THREAD_GSCOPE_IN_TCB 1 +diff --git a/sysdeps/csky/nptl/tls.h b/sysdeps/csky/nptl/tls.h +index 7a234041..f3fa3fcb 100644 +--- a/sysdeps/csky/nptl/tls.h ++++ b/sysdeps/csky/nptl/tls.h +@@ -116,15 +116,7 @@ typedef struct + # define DB_THREAD_SELF \ + CONST_THREAD_AREA (32, sizeof (struct pthread)) + +-/* Access to data in the thread descriptor is easy. */ +-# define THREAD_GETMEM(descr, member) \ +- descr->member +-# define THREAD_GETMEM_NC(descr, member, idx) \ +- descr->member[idx] +-# define THREAD_SETMEM(descr, member, value) \ +- descr->member = (value) +-# define THREAD_SETMEM_NC(descr, member, idx, value) \ +- descr->member[idx] = (value) ++# include + + /* Get and set the global scope generation counter in struct pthread. */ + # define THREAD_GSCOPE_IN_TCB 1 +diff --git a/sysdeps/hppa/nptl/tls.h b/sysdeps/hppa/nptl/tls.h +index 857003a7..f0e274c4 100644 +--- a/sysdeps/hppa/nptl/tls.h ++++ b/sysdeps/hppa/nptl/tls.h +@@ -107,15 +107,7 @@ typedef struct + # define DB_THREAD_SELF \ + REGISTER (32, 32, 53 * 4, -sizeof (struct pthread)) + +-/* Access to data in the thread descriptor is easy. */ +-# define THREAD_GETMEM(descr, member) \ +- descr->member +-# define THREAD_GETMEM_NC(descr, member, idx) \ +- descr->member[idx] +-# define THREAD_SETMEM(descr, member, value) \ +- descr->member = (value) +-# define THREAD_SETMEM_NC(descr, member, idx, value) \ +- descr->member[idx] = (value) ++# include + + static inline struct pthread *__get_cr27(void) + { +diff --git a/sysdeps/i386/nptl/tcb-access.h b/sysdeps/i386/nptl/tcb-access.h +new file mode 100644 +index 00000000..6c6d561e +--- /dev/null ++++ b/sysdeps/i386/nptl/tcb-access.h +@@ -0,0 +1,123 @@ ++/* THREAD_* accessors. i386 version. ++ Copyright (C) 2002-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 ++ . */ ++ ++/* Read member of the thread descriptor directly. */ ++#define THREAD_GETMEM(descr, member) \ ++ ({ __typeof (descr->member) __value; \ ++ _Static_assert (sizeof (__value) == 1 \ ++ || sizeof (__value) == 4 \ ++ || sizeof (__value) == 8, \ ++ "size of per-thread data"); \ ++ if (sizeof (__value) == 1) \ ++ asm volatile ("movb %%gs:%P2,%b0" \ ++ : "=q" (__value) \ ++ : "0" (0), "i" (offsetof (struct pthread, member))); \ ++ else if (sizeof (__value) == 4) \ ++ asm volatile ("movl %%gs:%P1,%0" \ ++ : "=r" (__value) \ ++ : "i" (offsetof (struct pthread, member))); \ ++ else /* 8 */ \ ++ { \ ++ asm volatile ("movl %%gs:%P1,%%eax\n\t" \ ++ "movl %%gs:%P2,%%edx" \ ++ : "=A" (__value) \ ++ : "i" (offsetof (struct pthread, member)), \ ++ "i" (offsetof (struct pthread, member) + 4)); \ ++ } \ ++ __value; }) ++ ++ ++/* Same as THREAD_GETMEM, but the member offset can be non-constant. */ ++#define THREAD_GETMEM_NC(descr, member, idx) \ ++ ({ __typeof (descr->member[0]) __value; \ ++ _Static_assert (sizeof (__value) == 1 \ ++ || sizeof (__value) == 4 \ ++ || sizeof (__value) == 8, \ ++ "size of per-thread data"); \ ++ if (sizeof (__value) == 1) \ ++ asm volatile ("movb %%gs:%P2(%3),%b0" \ ++ : "=q" (__value) \ ++ : "0" (0), "i" (offsetof (struct pthread, member[0])), \ ++ "r" (idx)); \ ++ else if (sizeof (__value) == 4) \ ++ asm volatile ("movl %%gs:%P1(,%2,4),%0" \ ++ : "=r" (__value) \ ++ : "i" (offsetof (struct pthread, member[0])), \ ++ "r" (idx)); \ ++ else /* 8 */ \ ++ { \ ++ asm volatile ("movl %%gs:%P1(,%2,8),%%eax\n\t" \ ++ "movl %%gs:4+%P1(,%2,8),%%edx" \ ++ : "=&A" (__value) \ ++ : "i" (offsetof (struct pthread, member[0])), \ ++ "r" (idx)); \ ++ } \ ++ __value; }) ++ ++ ++ ++/* Set member of the thread descriptor directly. */ ++#define THREAD_SETMEM(descr, member, value) \ ++ ({ \ ++ _Static_assert (sizeof (descr->member) == 1 \ ++ || sizeof (descr->member) == 4 \ ++ || sizeof (descr->member) == 8, \ ++ "size of per-thread data"); \ ++ if (sizeof (descr->member) == 1) \ ++ asm volatile ("movb %b0,%%gs:%P1" : \ ++ : "iq" (value), \ ++ "i" (offsetof (struct pthread, member))); \ ++ else if (sizeof (descr->member) == 4) \ ++ asm volatile ("movl %0,%%gs:%P1" : \ ++ : "ir" (value), \ ++ "i" (offsetof (struct pthread, member))); \ ++ else /* 8 */ \ ++ { \ ++ asm volatile ("movl %%eax,%%gs:%P1\n\t" \ ++ "movl %%edx,%%gs:%P2" : \ ++ : "A" ((uint64_t) cast_to_integer (value)), \ ++ "i" (offsetof (struct pthread, member)), \ ++ "i" (offsetof (struct pthread, member) + 4)); \ ++ }}) ++ ++ ++/* Same as THREAD_SETMEM, but the member offset can be non-constant. */ ++#define THREAD_SETMEM_NC(descr, member, idx, value) \ ++ ({ \ ++ _Static_assert (sizeof (descr->member[0]) == 1 \ ++ || sizeof (descr->member[0]) == 4 \ ++ || sizeof (descr->member[0]) == 8, \ ++ "size of per-thread data"); \ ++ if (sizeof (descr->member[0]) == 1) \ ++ asm volatile ("movb %b0,%%gs:%P1(%2)" : \ ++ : "iq" (value), \ ++ "i" (offsetof (struct pthread, member)), \ ++ "r" (idx)); \ ++ else if (sizeof (descr->member[0]) == 4) \ ++ asm volatile ("movl %0,%%gs:%P1(,%2,4)" : \ ++ : "ir" (value), \ ++ "i" (offsetof (struct pthread, member)), \ ++ "r" (idx)); \ ++ else /* 8 */ \ ++ { \ ++ asm volatile ("movl %%eax,%%gs:%P1(,%2,8)\n\t" \ ++ "movl %%edx,%%gs:4+%P1(,%2,8)" : \ ++ : "A" ((uint64_t) cast_to_integer (value)), \ ++ "i" (offsetof (struct pthread, member)), \ ++ "r" (idx)); \ ++ }}) +diff --git a/sysdeps/i386/nptl/tls.h b/sysdeps/i386/nptl/tls.h +index 86ee1ef3..111c9ee5 100644 +--- a/sysdeps/i386/nptl/tls.h ++++ b/sysdeps/i386/nptl/tls.h +@@ -250,113 +250,7 @@ tls_fill_user_desc (union user_desc_init *desc, + REGISTER_THREAD_AREA (32, offsetof (struct user_regs_struct, xgs), 3) \ + REGISTER_THREAD_AREA (64, 26 * 8, 3) /* x86-64's user_regs_struct->gs */ + +- +-/* Read member of the thread descriptor directly. */ +-# define THREAD_GETMEM(descr, member) \ +- ({ __typeof (descr->member) __value; \ +- _Static_assert (sizeof (__value) == 1 \ +- || sizeof (__value) == 4 \ +- || sizeof (__value) == 8, \ +- "size of per-thread data"); \ +- if (sizeof (__value) == 1) \ +- asm volatile ("movb %%gs:%P2,%b0" \ +- : "=q" (__value) \ +- : "0" (0), "i" (offsetof (struct pthread, member))); \ +- else if (sizeof (__value) == 4) \ +- asm volatile ("movl %%gs:%P1,%0" \ +- : "=r" (__value) \ +- : "i" (offsetof (struct pthread, member))); \ +- else /* 8 */ \ +- { \ +- asm volatile ("movl %%gs:%P1,%%eax\n\t" \ +- "movl %%gs:%P2,%%edx" \ +- : "=A" (__value) \ +- : "i" (offsetof (struct pthread, member)), \ +- "i" (offsetof (struct pthread, member) + 4)); \ +- } \ +- __value; }) +- +- +-/* Same as THREAD_GETMEM, but the member offset can be non-constant. */ +-# define THREAD_GETMEM_NC(descr, member, idx) \ +- ({ __typeof (descr->member[0]) __value; \ +- _Static_assert (sizeof (__value) == 1 \ +- || sizeof (__value) == 4 \ +- || sizeof (__value) == 8, \ +- "size of per-thread data"); \ +- if (sizeof (__value) == 1) \ +- asm volatile ("movb %%gs:%P2(%3),%b0" \ +- : "=q" (__value) \ +- : "0" (0), "i" (offsetof (struct pthread, member[0])), \ +- "r" (idx)); \ +- else if (sizeof (__value) == 4) \ +- asm volatile ("movl %%gs:%P1(,%2,4),%0" \ +- : "=r" (__value) \ +- : "i" (offsetof (struct pthread, member[0])), \ +- "r" (idx)); \ +- else /* 8 */ \ +- { \ +- asm volatile ("movl %%gs:%P1(,%2,8),%%eax\n\t" \ +- "movl %%gs:4+%P1(,%2,8),%%edx" \ +- : "=&A" (__value) \ +- : "i" (offsetof (struct pthread, member[0])), \ +- "r" (idx)); \ +- } \ +- __value; }) +- +- +- +-/* Set member of the thread descriptor directly. */ +-# define THREAD_SETMEM(descr, member, value) \ +- ({ \ +- _Static_assert (sizeof (descr->member) == 1 \ +- || sizeof (descr->member) == 4 \ +- || sizeof (descr->member) == 8, \ +- "size of per-thread data"); \ +- if (sizeof (descr->member) == 1) \ +- asm volatile ("movb %b0,%%gs:%P1" : \ +- : "iq" (value), \ +- "i" (offsetof (struct pthread, member))); \ +- else if (sizeof (descr->member) == 4) \ +- asm volatile ("movl %0,%%gs:%P1" : \ +- : "ir" (value), \ +- "i" (offsetof (struct pthread, member))); \ +- else /* 8 */ \ +- { \ +- asm volatile ("movl %%eax,%%gs:%P1\n\t" \ +- "movl %%edx,%%gs:%P2" : \ +- : "A" ((uint64_t) cast_to_integer (value)), \ +- "i" (offsetof (struct pthread, member)), \ +- "i" (offsetof (struct pthread, member) + 4)); \ +- }}) +- +- +-/* Same as THREAD_SETMEM, but the member offset can be non-constant. */ +-# define THREAD_SETMEM_NC(descr, member, idx, value) \ +- ({ \ +- _Static_assert (sizeof (descr->member[0]) == 1 \ +- || sizeof (descr->member[0]) == 4 \ +- || sizeof (descr->member[0]) == 8, \ +- "size of per-thread data"); \ +- if (sizeof (descr->member[0]) == 1) \ +- asm volatile ("movb %b0,%%gs:%P1(%2)" : \ +- : "iq" (value), \ +- "i" (offsetof (struct pthread, member)), \ +- "r" (idx)); \ +- else if (sizeof (descr->member[0]) == 4) \ +- asm volatile ("movl %0,%%gs:%P1(,%2,4)" : \ +- : "ir" (value), \ +- "i" (offsetof (struct pthread, member)), \ +- "r" (idx)); \ +- else /* 8 */ \ +- { \ +- asm volatile ("movl %%eax,%%gs:%P1(,%2,8)\n\t" \ +- "movl %%edx,%%gs:4+%P1(,%2,8)" : \ +- : "A" ((uint64_t) cast_to_integer (value)), \ +- "i" (offsetof (struct pthread, member)), \ +- "r" (idx)); \ +- }}) +- ++# include + + /* Set the stack guard field in TCB head. */ + #define THREAD_SET_STACK_GUARD(value) \ +diff --git a/sysdeps/ia64/nptl/tls.h b/sysdeps/ia64/nptl/tls.h +index 66d9bf31..26fe555c 100644 +--- a/sysdeps/ia64/nptl/tls.h ++++ b/sysdeps/ia64/nptl/tls.h +@@ -128,15 +128,7 @@ register struct pthread *__thread_self __asm__("r13"); + /* Magic for libthread_db to know how to do THREAD_SELF. */ + # define DB_THREAD_SELF REGISTER (64, 64, 13 * 8, -TLS_PRE_TCB_SIZE) + +-/* Access to data in the thread descriptor is easy. */ +-#define THREAD_GETMEM(descr, member) \ +- descr->member +-#define THREAD_GETMEM_NC(descr, member, idx) \ +- descr->member[idx] +-#define THREAD_SETMEM(descr, member, value) \ +- descr->member = (value) +-#define THREAD_SETMEM_NC(descr, member, idx, value) \ +- descr->member[idx] = (value) ++# include + + /* Set the stack guard field in TCB head. */ + #define THREAD_SET_STACK_GUARD(value) \ +diff --git a/sysdeps/m68k/nptl/tls.h b/sysdeps/m68k/nptl/tls.h +index cfcd6d2b..9f562c38 100644 +--- a/sysdeps/m68k/nptl/tls.h ++++ b/sysdeps/m68k/nptl/tls.h +@@ -118,15 +118,7 @@ extern void * __m68k_read_tp (void); + # define DB_THREAD_SELF \ + CONST_THREAD_AREA (32, TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE) + +-/* Access to data in the thread descriptor is easy. */ +-# define THREAD_GETMEM(descr, member) \ +- descr->member +-# define THREAD_GETMEM_NC(descr, member, idx) \ +- descr->member[idx] +-# define THREAD_SETMEM(descr, member, value) \ +- descr->member = (value) +-# define THREAD_SETMEM_NC(descr, member, idx, value) \ +- descr->member[idx] = (value) ++# include + + /* l_tls_offset == 0 is perfectly valid on M68K, so we have to use some + different value to mean unset l_tls_offset. */ +diff --git a/sysdeps/microblaze/nptl/tls.h b/sysdeps/microblaze/nptl/tls.h +index c93d90b1..bfa6efa7 100644 +--- a/sysdeps/microblaze/nptl/tls.h ++++ b/sysdeps/microblaze/nptl/tls.h +@@ -100,20 +100,7 @@ typedef struct + # define DB_THREAD_SELF \ + CONST_THREAD_AREA (32, sizeof (struct pthread)) + +-/* Read member of the thread descriptor directly. */ +-# define THREAD_GETMEM(descr, member) (descr->member) +- +-/* Same as THREAD_GETMEM, but the member offset can be non-constant. */ +-# define THREAD_GETMEM_NC(descr, member, idx) \ +- (descr->member[idx]) +- +-/* Set member of the thread descriptor directly. */ +-# define THREAD_SETMEM(descr, member, value) \ +- (descr->member = (value)) +- +-/* Same as THREAD_SETMEM, but the member offset can be non-constant. */ +-# define THREAD_SETMEM_NC(descr, member, idx, value) \ +- (descr->member[idx] = (value)) ++# include + + /* Get and set the global scope generation counter in struct pthread. */ + # define THREAD_GSCOPE_IN_TCB 1 +diff --git a/sysdeps/mips/nptl/tls.h b/sysdeps/mips/nptl/tls.h +index c09f4907..ef99aa64 100644 +--- a/sysdeps/mips/nptl/tls.h ++++ b/sysdeps/mips/nptl/tls.h +@@ -144,14 +144,7 @@ typedef struct + CONST_THREAD_AREA (32, TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE) + + /* Access to data in the thread descriptor is easy. */ +-# define THREAD_GETMEM(descr, member) \ +- descr->member +-# define THREAD_GETMEM_NC(descr, member, idx) \ +- descr->member[idx] +-# define THREAD_SETMEM(descr, member, value) \ +- descr->member = (value) +-# define THREAD_SETMEM_NC(descr, member, idx, value) \ +- descr->member[idx] = (value) ++# include + + /* l_tls_offset == 0 is perfectly valid on MIPS, so we have to use some + different value to mean unset l_tls_offset. */ +diff --git a/sysdeps/nios2/nptl/tls.h b/sysdeps/nios2/nptl/tls.h +index 02a05b4e..7110cfcc 100644 +--- a/sysdeps/nios2/nptl/tls.h ++++ b/sysdeps/nios2/nptl/tls.h +@@ -112,15 +112,7 @@ register struct pthread *__thread_self __asm__("r23"); + # define DB_THREAD_SELF \ + REGISTER (32, 32, 23 * 4, -TLS_PRE_TCB_SIZE - TLS_TCB_OFFSET) + +-/* Access to data in the thread descriptor is easy. */ +-# define THREAD_GETMEM(descr, member) \ +- descr->member +-# define THREAD_GETMEM_NC(descr, member, idx) \ +- descr->member[idx] +-# define THREAD_SETMEM(descr, member, value) \ +- descr->member = (value) +-# define THREAD_SETMEM_NC(descr, member, idx, value) \ +- descr->member[idx] = (value) ++# include + + # define THREAD_GET_POINTER_GUARD() \ + (((tcbhead_t *) (READ_THREAD_POINTER () \ +diff --git a/sysdeps/nptl/tcb-access.h b/sysdeps/nptl/tcb-access.h +new file mode 100644 +index 00000000..b4137b8a +--- /dev/null ++++ b/sysdeps/nptl/tcb-access.h +@@ -0,0 +1,30 @@ ++/* THREAD_* accessors. Generic version based on struct pthread pointers. ++ Copyright (C) 2002-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 ++ . */ ++ ++/* Note: These are for accessing the TCB of the *current* thread. ++ descr can be disregarded on some targets as an optimization. See ++ i386 for an example. */ ++ ++#define THREAD_GETMEM(descr, member) \ ++ descr->member ++#define THREAD_GETMEM_NC(descr, member, idx) \ ++ descr->member[idx] ++#define THREAD_SETMEM(descr, member, value) \ ++ descr->member = (value) ++#define THREAD_SETMEM_NC(descr, member, idx, value) \ ++ descr->member[idx] = (value) +diff --git a/sysdeps/powerpc/nptl/tls.h b/sysdeps/powerpc/nptl/tls.h +index 6c779b66..110d085d 100644 +--- a/sysdeps/powerpc/nptl/tls.h ++++ b/sysdeps/powerpc/nptl/tls.h +@@ -176,20 +176,7 @@ typedef struct + REGISTER (64, 64, PT_THREAD_POINTER * 8, \ + - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) + +-/* Read member of the thread descriptor directly. */ +-# define THREAD_GETMEM(descr, member) ((void)(descr), (THREAD_SELF)->member) +- +-/* Same as THREAD_GETMEM, but the member offset can be non-constant. */ +-# define THREAD_GETMEM_NC(descr, member, idx) \ +- ((void)(descr), (THREAD_SELF)->member[idx]) +- +-/* Set member of the thread descriptor directly. */ +-# define THREAD_SETMEM(descr, member, value) \ +- ((void)(descr), (THREAD_SELF)->member = (value)) +- +-/* Same as THREAD_SETMEM, but the member offset can be non-constant. */ +-# define THREAD_SETMEM_NC(descr, member, idx, value) \ +- ((void)(descr), (THREAD_SELF)->member[idx] = (value)) ++# include + + /* Set the stack guard field in TCB head. */ + # define THREAD_SET_STACK_GUARD(value) \ +diff --git a/sysdeps/riscv/nptl/tls.h b/sysdeps/riscv/nptl/tls.h +index 5350bcc0..bdc0a3a6 100644 +--- a/sysdeps/riscv/nptl/tls.h ++++ b/sysdeps/riscv/nptl/tls.h +@@ -105,14 +105,7 @@ typedef struct + REGISTER (64, 64, 4 * 8, - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) + + /* Access to data in the thread descriptor is easy. */ +-# define THREAD_GETMEM(descr, member) \ +- descr->member +-# define THREAD_GETMEM_NC(descr, member, idx) \ +- descr->member[idx] +-# define THREAD_SETMEM(descr, member, value) \ +- descr->member = (value) +-# define THREAD_SETMEM_NC(descr, member, idx, value) \ +- descr->member[idx] = (value) ++# include + + /* l_tls_offset == 0 is perfectly valid, so we have to use some different + value to mean unset l_tls_offset. */ +diff --git a/sysdeps/s390/nptl/tls.h b/sysdeps/s390/nptl/tls.h +index efb52515..2cdd18eb 100644 +--- a/sysdeps/s390/nptl/tls.h ++++ b/sysdeps/s390/nptl/tls.h +@@ -135,15 +135,7 @@ typedef struct + # define DB_THREAD_SELF REGISTER (32, 32, 18 * 4, 0) \ + REGISTER (64, __WORDSIZE, 18 * 8, 0) + +-/* Access to data in the thread descriptor is easy. */ +-#define THREAD_GETMEM(descr, member) \ +- descr->member +-#define THREAD_GETMEM_NC(descr, member, idx) \ +- descr->member[idx] +-#define THREAD_SETMEM(descr, member, value) \ +- descr->member = (value) +-#define THREAD_SETMEM_NC(descr, member, idx, value) \ +- descr->member[idx] = (value) ++# include + + /* Set the stack guard field in TCB head. */ + #define THREAD_SET_STACK_GUARD(value) \ +diff --git a/sysdeps/sh/nptl/tls.h b/sysdeps/sh/nptl/tls.h +index ac3c9a9e..39064002 100644 +--- a/sysdeps/sh/nptl/tls.h ++++ b/sysdeps/sh/nptl/tls.h +@@ -113,19 +113,7 @@ typedef struct + # define DB_THREAD_SELF \ + REGISTER (32, 32, REG_GBR * 4, -sizeof (struct pthread)) + +-/* Read member of the thread descriptor directly. */ +-# define THREAD_GETMEM(descr, member) (descr->member) +- +-/* Same as THREAD_GETMEM, but the member offset can be non-constant. */ +-# define THREAD_GETMEM_NC(descr, member, idx) (descr->member[idx]) +- +-/* Set member of the thread descriptor directly. */ +-# define THREAD_SETMEM(descr, member, value) \ +- descr->member = (value) +- +-/* Same as THREAD_SETMEM, but the member offset can be non-constant. */ +-# define THREAD_SETMEM_NC(descr, member, idx, value) \ +- descr->member[idx] = (value) ++# include + + #define THREAD_GET_POINTER_GUARD() \ + ({ tcbhead_t *__tcbp; \ +diff --git a/sysdeps/sparc/nptl/tls.h b/sysdeps/sparc/nptl/tls.h +index dd1eb82a..376d7299 100644 +--- a/sysdeps/sparc/nptl/tls.h ++++ b/sysdeps/sparc/nptl/tls.h +@@ -112,15 +112,7 @@ register struct pthread *__thread_self __asm__("%g7"); + REGISTER (32, 32, 10 * 4, 0) \ + REGISTER (64, __WORDSIZE, (6 * 8) + (__WORDSIZE==64?0:4), 0) + +-/* Access to data in the thread descriptor is easy. */ +-#define THREAD_GETMEM(descr, member) \ +- descr->member +-#define THREAD_GETMEM_NC(descr, member, idx) \ +- descr->member[idx] +-#define THREAD_SETMEM(descr, member, value) \ +- descr->member = (value) +-#define THREAD_SETMEM_NC(descr, member, idx, value) \ +- descr->member[idx] = (value) ++# include + + /* Set the stack guard field in TCB head. */ + #define THREAD_SET_STACK_GUARD(value) \ +diff --git a/sysdeps/x86_64/nptl/tcb-access.h b/sysdeps/x86_64/nptl/tcb-access.h +new file mode 100644 +index 00000000..18848a72 +--- /dev/null ++++ b/sysdeps/x86_64/nptl/tcb-access.h +@@ -0,0 +1,130 @@ ++/* THREAD_* accessors. x86_64 version. ++ Copyright (C) 2002-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 ++ . */ ++ ++/* Read member of the thread descriptor directly. */ ++# define THREAD_GETMEM(descr, member) \ ++ ({ __typeof (descr->member) __value; \ ++ _Static_assert (sizeof (__value) == 1 \ ++ || sizeof (__value) == 4 \ ++ || sizeof (__value) == 8, \ ++ "size of per-thread data"); \ ++ if (sizeof (__value) == 1) \ ++ asm volatile ("movb %%fs:%P2,%b0" \ ++ : "=q" (__value) \ ++ : "0" (0), "i" (offsetof (struct pthread, member))); \ ++ else if (sizeof (__value) == 4) \ ++ asm volatile ("movl %%fs:%P1,%0" \ ++ : "=r" (__value) \ ++ : "i" (offsetof (struct pthread, member))); \ ++ else /* 8 */ \ ++ { \ ++ asm volatile ("movq %%fs:%P1,%q0" \ ++ : "=r" (__value) \ ++ : "i" (offsetof (struct pthread, member))); \ ++ } \ ++ __value; }) ++ ++ ++/* Same as THREAD_GETMEM, but the member offset can be non-constant. */ ++# define THREAD_GETMEM_NC(descr, member, idx) \ ++ ({ __typeof (descr->member[0]) __value; \ ++ _Static_assert (sizeof (__value) == 1 \ ++ || sizeof (__value) == 4 \ ++ || sizeof (__value) == 8, \ ++ "size of per-thread data"); \ ++ if (sizeof (__value) == 1) \ ++ asm volatile ("movb %%fs:%P2(%q3),%b0" \ ++ : "=q" (__value) \ ++ : "0" (0), "i" (offsetof (struct pthread, member[0])), \ ++ "r" (idx)); \ ++ else if (sizeof (__value) == 4) \ ++ asm volatile ("movl %%fs:%P1(,%q2,4),%0" \ ++ : "=r" (__value) \ ++ : "i" (offsetof (struct pthread, member[0])), "r" (idx));\ ++ else /* 8 */ \ ++ { \ ++ asm volatile ("movq %%fs:%P1(,%q2,8),%q0" \ ++ : "=r" (__value) \ ++ : "i" (offsetof (struct pthread, member[0])), \ ++ "r" (idx)); \ ++ } \ ++ __value; }) ++ ++ ++/* Loading addresses of objects on x86-64 needs to be treated special ++ when generating PIC code. */ ++#ifdef __pic__ ++# define IMM_MODE "nr" ++#else ++# define IMM_MODE "ir" ++#endif ++ ++ ++/* Set member of the thread descriptor directly. */ ++# define THREAD_SETMEM(descr, member, value) \ ++ ({ \ ++ _Static_assert (sizeof (descr->member) == 1 \ ++ || sizeof (descr->member) == 4 \ ++ || sizeof (descr->member) == 8, \ ++ "size of per-thread data"); \ ++ if (sizeof (descr->member) == 1) \ ++ asm volatile ("movb %b0,%%fs:%P1" : \ ++ : "iq" (value), \ ++ "i" (offsetof (struct pthread, member))); \ ++ else if (sizeof (descr->member) == 4) \ ++ asm volatile ("movl %0,%%fs:%P1" : \ ++ : IMM_MODE (value), \ ++ "i" (offsetof (struct pthread, member))); \ ++ else /* 8 */ \ ++ { \ ++ /* Since movq takes a signed 32-bit immediate or a register source \ ++ operand, use "er" constraint for 32-bit signed integer constant \ ++ or register. */ \ ++ asm volatile ("movq %q0,%%fs:%P1" : \ ++ : "er" ((uint64_t) cast_to_integer (value)), \ ++ "i" (offsetof (struct pthread, member))); \ ++ }}) ++ ++ ++/* Same as THREAD_SETMEM, but the member offset can be non-constant. */ ++# define THREAD_SETMEM_NC(descr, member, idx, value) \ ++ ({ \ ++ _Static_assert (sizeof (descr->member[0]) == 1 \ ++ || sizeof (descr->member[0]) == 4 \ ++ || sizeof (descr->member[0]) == 8, \ ++ "size of per-thread data"); \ ++ if (sizeof (descr->member[0]) == 1) \ ++ asm volatile ("movb %b0,%%fs:%P1(%q2)" : \ ++ : "iq" (value), \ ++ "i" (offsetof (struct pthread, member[0])), \ ++ "r" (idx)); \ ++ else if (sizeof (descr->member[0]) == 4) \ ++ asm volatile ("movl %0,%%fs:%P1(,%q2,4)" : \ ++ : IMM_MODE (value), \ ++ "i" (offsetof (struct pthread, member[0])), \ ++ "r" (idx)); \ ++ else /* 8 */ \ ++ { \ ++ /* Since movq takes a signed 32-bit immediate or a register source \ ++ operand, use "er" constraint for 32-bit signed integer constant \ ++ or register. */ \ ++ asm volatile ("movq %q0,%%fs:%P1(,%q2,8)" : \ ++ : "er" ((uint64_t) cast_to_integer (value)), \ ++ "i" (offsetof (struct pthread, member[0])), \ ++ "r" (idx)); \ ++ }}) +diff --git a/sysdeps/x86_64/nptl/tls.h b/sysdeps/x86_64/nptl/tls.h +index a78c4f4d..3af1836e 100644 +--- a/sysdeps/x86_64/nptl/tls.h ++++ b/sysdeps/x86_64/nptl/tls.h +@@ -195,119 +195,7 @@ _Static_assert (offsetof (tcbhead_t, __glibc_unused2) == 0x80, + # define DB_THREAD_SELF_INCLUDE /* For the FS constant. */ + # define DB_THREAD_SELF CONST_THREAD_AREA (64, FS) + +-/* Read member of the thread descriptor directly. */ +-# define THREAD_GETMEM(descr, member) \ +- ({ __typeof (descr->member) __value; \ +- _Static_assert (sizeof (__value) == 1 \ +- || sizeof (__value) == 4 \ +- || sizeof (__value) == 8, \ +- "size of per-thread data"); \ +- if (sizeof (__value) == 1) \ +- asm volatile ("movb %%fs:%P2,%b0" \ +- : "=q" (__value) \ +- : "0" (0), "i" (offsetof (struct pthread, member))); \ +- else if (sizeof (__value) == 4) \ +- asm volatile ("movl %%fs:%P1,%0" \ +- : "=r" (__value) \ +- : "i" (offsetof (struct pthread, member))); \ +- else /* 8 */ \ +- { \ +- asm volatile ("movq %%fs:%P1,%q0" \ +- : "=r" (__value) \ +- : "i" (offsetof (struct pthread, member))); \ +- } \ +- __value; }) +- +- +-/* Same as THREAD_GETMEM, but the member offset can be non-constant. */ +-# define THREAD_GETMEM_NC(descr, member, idx) \ +- ({ __typeof (descr->member[0]) __value; \ +- _Static_assert (sizeof (__value) == 1 \ +- || sizeof (__value) == 4 \ +- || sizeof (__value) == 8, \ +- "size of per-thread data"); \ +- if (sizeof (__value) == 1) \ +- asm volatile ("movb %%fs:%P2(%q3),%b0" \ +- : "=q" (__value) \ +- : "0" (0), "i" (offsetof (struct pthread, member[0])), \ +- "r" (idx)); \ +- else if (sizeof (__value) == 4) \ +- asm volatile ("movl %%fs:%P1(,%q2,4),%0" \ +- : "=r" (__value) \ +- : "i" (offsetof (struct pthread, member[0])), "r" (idx));\ +- else /* 8 */ \ +- { \ +- asm volatile ("movq %%fs:%P1(,%q2,8),%q0" \ +- : "=r" (__value) \ +- : "i" (offsetof (struct pthread, member[0])), \ +- "r" (idx)); \ +- } \ +- __value; }) +- +- +-/* Loading addresses of objects on x86-64 needs to be treated special +- when generating PIC code. */ +-#ifdef __pic__ +-# define IMM_MODE "nr" +-#else +-# define IMM_MODE "ir" +-#endif +- +- +-/* Set member of the thread descriptor directly. */ +-# define THREAD_SETMEM(descr, member, value) \ +- ({ \ +- _Static_assert (sizeof (descr->member) == 1 \ +- || sizeof (descr->member) == 4 \ +- || sizeof (descr->member) == 8, \ +- "size of per-thread data"); \ +- if (sizeof (descr->member) == 1) \ +- asm volatile ("movb %b0,%%fs:%P1" : \ +- : "iq" (value), \ +- "i" (offsetof (struct pthread, member))); \ +- else if (sizeof (descr->member) == 4) \ +- asm volatile ("movl %0,%%fs:%P1" : \ +- : IMM_MODE (value), \ +- "i" (offsetof (struct pthread, member))); \ +- else /* 8 */ \ +- { \ +- /* Since movq takes a signed 32-bit immediate or a register source \ +- operand, use "er" constraint for 32-bit signed integer constant \ +- or register. */ \ +- asm volatile ("movq %q0,%%fs:%P1" : \ +- : "er" ((uint64_t) cast_to_integer (value)), \ +- "i" (offsetof (struct pthread, member))); \ +- }}) +- +- +-/* Same as THREAD_SETMEM, but the member offset can be non-constant. */ +-# define THREAD_SETMEM_NC(descr, member, idx, value) \ +- ({ \ +- _Static_assert (sizeof (descr->member[0]) == 1 \ +- || sizeof (descr->member[0]) == 4 \ +- || sizeof (descr->member[0]) == 8, \ +- "size of per-thread data"); \ +- if (sizeof (descr->member[0]) == 1) \ +- asm volatile ("movb %b0,%%fs:%P1(%q2)" : \ +- : "iq" (value), \ +- "i" (offsetof (struct pthread, member[0])), \ +- "r" (idx)); \ +- else if (sizeof (descr->member[0]) == 4) \ +- asm volatile ("movl %0,%%fs:%P1(,%q2,4)" : \ +- : IMM_MODE (value), \ +- "i" (offsetof (struct pthread, member[0])), \ +- "r" (idx)); \ +- else /* 8 */ \ +- { \ +- /* Since movq takes a signed 32-bit immediate or a register source \ +- operand, use "er" constraint for 32-bit signed integer constant \ +- or register. */ \ +- asm volatile ("movq %q0,%%fs:%P1(,%q2,8)" : \ +- : "er" ((uint64_t) cast_to_integer (value)), \ +- "i" (offsetof (struct pthread, member[0])), \ +- "r" (idx)); \ +- }}) +- ++# include + + /* Set the stack guard field in TCB head. */ + # define THREAD_SET_STACK_GUARD(value) \ +-- +2.23.0 + diff --git a/rseq-nptl-rseq-failure-after-registration-on-main-thread-.patch b/rseq-nptl-rseq-failure-after-registration-on-main-thread-.patch new file mode 100644 index 0000000000000000000000000000000000000000..7fd271a2b562aafc6f602de04c31a940ccb37856 --- /dev/null +++ b/rseq-nptl-rseq-failure-after-registration-on-main-thread-.patch @@ -0,0 +1,44 @@ +From 210967ce32172eb7356747ed0b655e1fc37d0c57 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Thu, 9 Dec 2021 09:49:32 +0100 +Subject: [PATCH 8/9] nptl: rseq failure after registration on main thread is + fatal + +This simplifies the application programming model. + +Browser sandboxes have already been fixed: + + Sandbox is incompatible with rseq registration + + + Allow rseq in the Linux sandboxes. r=gcp + + + Sandbox needs to support rseq system call + + + Linux sandbox: Allow rseq(2) + + +Reviewed-by: Szabolcs Nagy +--- + nptl/pthread_create.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c +index f405fa35..109c5e3d 100644 +--- a/nptl/pthread_create.c ++++ b/nptl/pthread_create.c +@@ -371,7 +371,8 @@ start_thread (void *arg) + /* Register rseq TLS to the kernel. */ + { + bool do_rseq = THREAD_GETMEM (pd, flags) & ATTR_FLAG_DO_RSEQ; +- rseq_register_current_thread (pd, do_rseq); ++ if (!rseq_register_current_thread (pd, do_rseq) && do_rseq) ++ __libc_fatal ("Fatal glibc error: rseq registration failed\n"); + } + + #ifndef __ASSUME_SET_ROBUST_LIST +-- +2.23.0 + diff --git a/rt-Set-the-correct-message-queue-for-tst-mqueue10.patch b/rt-Set-the-correct-message-queue-for-tst-mqueue10.patch new file mode 100644 index 0000000000000000000000000000000000000000..700045ab8e3b9fc9e48bdae7197fc34394659656 --- /dev/null +++ b/rt-Set-the-correct-message-queue-for-tst-mqueue10.patch @@ -0,0 +1,35 @@ +From 3d9a539ee66165148b2b9e08b46e03a5f58f65d2 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Wed, 4 Aug 2021 17:14:46 -0300 +Subject: [PATCH] rt: Set the correct message queue for tst-mqueue10 + +Checked on x86_64-linux-gnu. +--- + rt/tst-mqueue10.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/rt/tst-mqueue10.c b/rt/tst-mqueue10.c +index 1879580..0bf64d7 100644 +--- a/rt/tst-mqueue10.c ++++ b/rt/tst-mqueue10.c +@@ -25,7 +25,7 @@ + #include + #include + +-static char name[sizeof "/tst-mqueue2-" + INT_BUFSIZE_BOUND (pid_t)]; ++static char name[sizeof "/tst-mqueue10-" + INT_BUFSIZE_BOUND (pid_t)]; + + static void + do_cleanup (void) +@@ -37,7 +37,7 @@ do_cleanup (void) + static int + do_test (void) + { +- snprintf (name, sizeof (name), "/tst-mqueue2-%u", getpid ()); ++ snprintf (name, sizeof (name), "/tst-mqueue10-%u", getpid ()); + + char msg[8] = { 0x55 }; + +-- +1.8.3.1 + diff --git a/rtld-copy-terminating-null-in-tunables_strdup-bug-28.patch b/rtld-copy-terminating-null-in-tunables_strdup-bug-28.patch new file mode 100644 index 0000000000000000000000000000000000000000..6f7310675b7dff8397b34f4830587290154c59d3 --- /dev/null +++ b/rtld-copy-terminating-null-in-tunables_strdup-bug-28.patch @@ -0,0 +1,28 @@ +From a4f5a3103fc3e7974dbe35b411cba9f670807cde Mon Sep 17 00:00:00 2001 +From: Andreas Schwab +Date: Mon, 23 Aug 2021 10:19:52 +0200 +Subject: [PATCH] rtld: copy terminating null in tunables_strdup (bug 28256) + +Avoid triggering a false positive from valgrind by copying the terminating +null in tunables_strdup. At this point the heap is still clean, but +valgrind is stricter here. +--- + elf/dl-tunables.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c +index 8009e54..1666736 100644 +--- a/elf/dl-tunables.c ++++ b/elf/dl-tunables.c +@@ -56,8 +56,6 @@ tunables_strdup (const char *in) + if (out == (void *)-1) + _dl_fatal_printf ("sbrk() failure while processing tunables\n"); + +- i--; +- + while (i-- > 0) + out[i] = in[i]; + +-- +1.8.3.1 + diff --git a/socket-Add-the-__sockaddr_un_set-function.patch b/socket-Add-the-__sockaddr_un_set-function.patch new file mode 100644 index 0000000000000000000000000000000000000000..0b0997b7d26b5199aae91fb745c89455242ed90d --- /dev/null +++ b/socket-Add-the-__sockaddr_un_set-function.patch @@ -0,0 +1,174 @@ +From e368b12f6c16b6888dda99ba641e999b9c9643c8 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Mon, 17 Jan 2022 10:21:34 +0100 +Subject: [PATCH] socket: Add the __sockaddr_un_set function + +Reviewed-by: Siddhesh Poyarekar +--- + include/sys/un.h | 12 +++++++++ + socket/Makefile | 6 ++++- + socket/sockaddr_un_set.c | 41 +++++++++++++++++++++++++++++ + socket/tst-sockaddr_un_set.c | 62 ++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 120 insertions(+), 1 deletion(-) + create mode 100644 socket/sockaddr_un_set.c + create mode 100644 socket/tst-sockaddr_un_set.c + +diff --git a/include/sys/un.h b/include/sys/un.h +index bdbee99..152afd9 100644 +--- a/include/sys/un.h ++++ b/include/sys/un.h +@@ -1 +1,13 @@ + #include ++ ++#ifndef _ISOMAC ++ ++/* Set ADDR->sun_family to AF_UNIX and ADDR->sun_path to PATHNAME. ++ Return 0 on success or -1 on failure (due to overlong PATHNAME). ++ The caller should always use sizeof (struct sockaddr_un) as the ++ socket address length, disregaring the length of PATHNAME. ++ Only concrete (non-abstract) pathnames are supported. */ ++int __sockaddr_un_set (struct sockaddr_un *addr, const char *pathname) ++ attribute_hidden; ++ ++#endif /* _ISOMAC */ +diff --git a/socket/Makefile b/socket/Makefile +index 39333e1..156eec6 100644 +--- a/socket/Makefile ++++ b/socket/Makefile +@@ -29,13 +29,17 @@ headers := sys/socket.h sys/un.h bits/sockaddr.h bits/socket.h \ + routines := accept bind connect getpeername getsockname getsockopt \ + listen recv recvfrom recvmsg send sendmsg sendto \ + setsockopt shutdown socket socketpair isfdtype opensock \ +- sockatmark accept4 recvmmsg sendmmsg ++ sockatmark accept4 recvmmsg sendmmsg sockaddr_un_set + + tests := \ + tst-accept4 \ + tst-sockopt \ + # tests + ++tests-internal := \ ++ tst-sockaddr_un_set \ ++ # tests-internal ++ + tests-time64 := \ + tst-sockopt-time64 \ + # tests +diff --git a/socket/sockaddr_un_set.c b/socket/sockaddr_un_set.c +new file mode 100644 +index 0000000..0bd40dc +--- /dev/null ++++ b/socket/sockaddr_un_set.c +@@ -0,0 +1,41 @@ ++/* Set the sun_path member of struct sockaddr_un. ++ Copyright (C) 2022 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++int ++__sockaddr_un_set (struct sockaddr_un *addr, const char *pathname) ++{ ++ size_t name_length = strlen (pathname); ++ ++ /* The kernel supports names of exactly sizeof (addr->sun_path) ++ bytes, without a null terminator, but userspace does not; see the ++ SUN_LEN macro. */ ++ if (name_length >= sizeof (addr->sun_path)) ++ { ++ __set_errno (EINVAL); /* Error code used by the kernel. */ ++ return -1; ++ } ++ ++ addr->sun_family = AF_UNIX; ++ memcpy (addr->sun_path, pathname, name_length + 1); ++ return 0; ++} +diff --git a/socket/tst-sockaddr_un_set.c b/socket/tst-sockaddr_un_set.c +new file mode 100644 +index 0000000..29c2a81 +--- /dev/null ++++ b/socket/tst-sockaddr_un_set.c +@@ -0,0 +1,62 @@ ++/* Test the __sockaddr_un_set function. ++ Copyright (C) 2022 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 ++ . */ ++ ++/* Re-compile the function because the version in libc is not ++ exported. */ ++#include "sockaddr_un_set.c" ++ ++#include ++ ++static int ++do_test (void) ++{ ++ struct sockaddr_un sun; ++ ++ memset (&sun, 0xcc, sizeof (sun)); ++ __sockaddr_un_set (&sun, ""); ++ TEST_COMPARE (sun.sun_family, AF_UNIX); ++ TEST_COMPARE (__sockaddr_un_set (&sun, ""), 0); ++ ++ memset (&sun, 0xcc, sizeof (sun)); ++ TEST_COMPARE (__sockaddr_un_set (&sun, "/example"), 0); ++ TEST_COMPARE_STRING (sun.sun_path, "/example"); ++ ++ { ++ char pathname[108]; /* Length of sun_path (ABI constant). */ ++ memset (pathname, 'x', sizeof (pathname)); ++ pathname[sizeof (pathname) - 1] = '\0'; ++ memset (&sun, 0xcc, sizeof (sun)); ++ TEST_COMPARE (__sockaddr_un_set (&sun, pathname), 0); ++ TEST_COMPARE (sun.sun_family, AF_UNIX); ++ TEST_COMPARE_STRING (sun.sun_path, pathname); ++ } ++ ++ { ++ char pathname[109]; ++ memset (pathname, 'x', sizeof (pathname)); ++ pathname[sizeof (pathname) - 1] = '\0'; ++ memset (&sun, 0xcc, sizeof (sun)); ++ errno = 0; ++ TEST_COMPARE (__sockaddr_un_set (&sun, pathname), -1); ++ TEST_COMPARE (errno, EINVAL); ++ } ++ ++ return 0; ++} ++ ++#include +-- +1.8.3.1 + diff --git a/socket-Do-not-use-AF_NETLINK-in-__opensock.patch b/socket-Do-not-use-AF_NETLINK-in-__opensock.patch new file mode 100644 index 0000000000000000000000000000000000000000..d78b010628cbe9a58b6179784dc8bd0a50f7d608 --- /dev/null +++ b/socket-Do-not-use-AF_NETLINK-in-__opensock.patch @@ -0,0 +1,40 @@ +From 6eaf10cbb78d22eae7999d9de55f6b93999e0860 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Mon, 22 Nov 2021 14:41:14 +0100 +Subject: [PATCH] socket: Do not use AF_NETLINK in __opensock + +It is not possible to use interface ioctls with netlink sockets +on all Linux kernels. + +Reviewed-by: Adhemerval Zanella +(cherry picked from commit 3d981795cd00cc9b73c3ee5087c308361acd62e5) +--- + socket/opensock.c | 9 +-------- + 1 file changed, 1 insertion(+), 8 deletions(-) + +diff --git a/socket/opensock.c b/socket/opensock.c +index ff94d27a61..3e35821f91 100644 +--- a/socket/opensock.c ++++ b/socket/opensock.c +@@ -24,17 +24,10 @@ + int + __opensock (void) + { +- /* SOCK_DGRAM is supported by all address families. (Netlink does +- not support SOCK_STREAM.) */ ++ /* SOCK_DGRAM is supported by all address families. */ + int type = SOCK_DGRAM | SOCK_CLOEXEC; + int fd; + +-#ifdef AF_NETLINK +- fd = __socket (AF_NETLINK, type, 0); +- if (fd >= 0) +- return fd; +-#endif +- + fd = __socket (AF_UNIX, type, 0); + if (fd >= 0) + return fd; +-- +2.27.0 + diff --git a/stdlib-Fix-formatting-of-tests-list-in-Makefile.patch b/stdlib-Fix-formatting-of-tests-list-in-Makefile.patch new file mode 100644 index 0000000000000000000000000000000000000000..db49888634974c9304b959f102345c3b50a94d74 --- /dev/null +++ b/stdlib-Fix-formatting-of-tests-list-in-Makefile.patch @@ -0,0 +1,178 @@ +From 73c362840c4efde45125a6c27bf41726397f4038 Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +Date: Thu, 13 Jan 2022 18:50:55 +0530 +Subject: [PATCH] stdlib: Fix formatting of tests list in Makefile + +Signed-off-by: Siddhesh Poyarekar +Reviewed-by: Florian Weimer +(cherry picked from commit f9dab1b5f23d0fb008a56c7c6c8919adb49d3611) +--- + stdlib/Makefile | 152 ++++++++++++++++++++++++++++---------------------------- + 1 file changed, 77 insertions(+), 75 deletions(-) + +diff --git a/stdlib/Makefile b/stdlib/Makefile +index 6a1c358..9bb5c22 100644 +--- a/stdlib/Makefile ++++ b/stdlib/Makefile +@@ -65,81 +65,83 @@ aux = grouping groupingwc tens_in_limb + static-only-routines = atexit at_quick_exit + + test-srcs := tst-fmtmsg +-tests := bug-fmtmsg1 \ +- bug-getcontext \ +- bug-strtod \ +- bug-strtod2 \ +- test-a64l \ +- test-at_quick_exit-race \ +- test-atexit-race \ +- test-bz22786 \ +- test-canon \ +- test-canon2 \ +- test-cxa_atexit-race \ +- test-cxa_atexit-race2 \ +- test-dlclose-exit-race \ +- test-on_exit-race \ +- testdiv \ +- testmb \ +- testmb2 \ +- testrand \ +- testsort \ +- tst-at_quick_exit \ +- tst-atexit \ +- tst-atof1 \ +- tst-atof2 \ +- tst-bsearch \ +- tst-bz20544 \ +- tst-canon-bz26341 \ +- tst-cxa_atexit \ +- tst-environ \ +- tst-getrandom \ +- tst-limits \ +- tst-makecontext \ +- tst-makecontext-align \ +- tst-makecontext2 \ +- tst-makecontext3 \ +- tst-on_exit \ +- tst-qsort \ +- tst-qsort2 \ +- tst-quick_exit \ +- tst-rand48 \ +- tst-rand48-2 \ +- tst-random \ +- tst-random2 \ +- tst-realpath \ +- tst-secure-getenv \ +- tst-setcontext \ +- tst-setcontext2 \ +- tst-setcontext3 \ +- tst-setcontext4 \ +- tst-setcontext5 \ +- tst-setcontext6 \ +- tst-setcontext7 \ +- tst-setcontext8 \ +- tst-setcontext9 \ +- tst-strfmon_l \ +- tst-strfrom \ +- tst-strfrom-locale \ +- tst-strtod \ +- tst-strtod-nan-locale \ +- tst-strtod-nan-sign \ +- tst-strtod-overflow \ +- tst-strtod-round \ +- tst-strtod-underflow \ +- tst-strtod2 \ +- tst-strtod5 \ +- tst-strtod6 \ +- tst-strtol \ +- tst-strtol-locale \ +- tst-strtoll \ +- tst-swapcontext1 \ +- tst-thread-quick_exit \ +- tst-tininess \ +- tst-unsetenv1 \ +- tst-width \ +- tst-width-stdint \ +- tst-xpg-basename ++tests := \ ++ bug-fmtmsg1 \ ++ bug-getcontext \ ++ bug-strtod \ ++ bug-strtod2 \ ++ test-a64l \ ++ test-at_quick_exit-race \ ++ test-atexit-race \ ++ test-bz22786 \ ++ test-canon \ ++ test-canon2 \ ++ test-cxa_atexit-race \ ++ test-cxa_atexit-race2 \ ++ test-dlclose-exit-race \ ++ test-on_exit-race \ ++ testdiv \ ++ testmb \ ++ testmb2 \ ++ testrand \ ++ testsort \ ++ tst-at_quick_exit \ ++ tst-atexit \ ++ tst-atof1 \ ++ tst-atof2 \ ++ tst-bsearch \ ++ tst-bz20544 \ ++ tst-canon-bz26341 \ ++ tst-cxa_atexit \ ++ tst-environ \ ++ tst-getrandom \ ++ tst-limits \ ++ tst-makecontext \ ++ tst-makecontext-align \ ++ tst-makecontext2 \ ++ tst-makecontext3 \ ++ tst-on_exit \ ++ tst-qsort \ ++ tst-qsort2 \ ++ tst-quick_exit \ ++ tst-rand48 \ ++ tst-rand48-2 \ ++ tst-random \ ++ tst-random2 \ ++ tst-realpath \ ++ tst-secure-getenv \ ++ tst-setcontext \ ++ tst-setcontext2 \ ++ tst-setcontext3 \ ++ tst-setcontext4 \ ++ tst-setcontext5 \ ++ tst-setcontext6 \ ++ tst-setcontext7 \ ++ tst-setcontext8 \ ++ tst-setcontext9 \ ++ tst-strfmon_l \ ++ tst-strfrom \ ++ tst-strfrom-locale \ ++ tst-strtod \ ++ tst-strtod-nan-locale \ ++ tst-strtod-nan-sign \ ++ tst-strtod-overflow \ ++ tst-strtod-round \ ++ tst-strtod-underflow \ ++ tst-strtod2 \ ++ tst-strtod5 \ ++ tst-strtod6 \ ++ tst-strtol \ ++ tst-strtol-locale \ ++ tst-strtoll \ ++ tst-swapcontext1 \ ++ tst-thread-quick_exit \ ++ tst-tininess \ ++ tst-unsetenv1 \ ++ tst-width \ ++ tst-width-stdint \ ++ tst-xpg-basename \ ++# tests + + tests-internal := tst-strtod1i tst-strtod3 tst-strtod4 tst-strtod5i \ + tst-tls-atexit tst-tls-atexit-nodelete +-- +1.8.3.1 + diff --git a/stdlib-Sort-tests-in-Makefile.patch b/stdlib-Sort-tests-in-Makefile.patch new file mode 100644 index 0000000000000000000000000000000000000000..2e1cdf1804124a1172cc86e35c47091217543676 --- /dev/null +++ b/stdlib-Sort-tests-in-Makefile.patch @@ -0,0 +1,126 @@ +From 269eb9d930546ce57e83b56c44c430f154684a23 Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +Date: Thu, 13 Jan 2022 10:34:37 +0530 +Subject: [PATCH] stdlib: Sort tests in Makefile + +Put one test per line and sort them. + +Signed-off-by: Siddhesh Poyarekar +(cherry picked from commit 5b766603efa727c236a5f0cdcf09b71ff60b7584) +--- + stdlib/Makefile | 99 +++++++++++++++++++++++++++++++++++++++++++-------------- + 1 file changed, 75 insertions(+), 24 deletions(-) + +diff --git a/stdlib/Makefile b/stdlib/Makefile +index 7c15549..6a1c358 100644 +--- a/stdlib/Makefile ++++ b/stdlib/Makefile +@@ -65,30 +65,81 @@ aux = grouping groupingwc tens_in_limb + static-only-routines = atexit at_quick_exit + + test-srcs := tst-fmtmsg +-tests := tst-strtol tst-strtod testmb testrand testsort testdiv \ +- test-canon test-canon2 tst-strtoll tst-environ \ +- tst-xpg-basename tst-random tst-random2 tst-bsearch \ +- tst-limits tst-rand48 bug-strtod tst-setcontext \ +- tst-setcontext2 test-a64l tst-qsort testmb2 \ +- bug-strtod2 tst-atof1 tst-atof2 tst-strtod2 \ +- tst-rand48-2 tst-makecontext tst-strtod5 \ +- tst-qsort2 tst-makecontext2 tst-strtod6 tst-unsetenv1 \ +- tst-makecontext3 bug-getcontext bug-fmtmsg1 \ +- tst-secure-getenv tst-strtod-overflow tst-strtod-round \ +- tst-tininess tst-strtod-underflow tst-setcontext3 \ +- tst-strtol-locale tst-strtod-nan-locale tst-strfmon_l \ +- tst-quick_exit tst-thread-quick_exit tst-width \ +- tst-width-stdint tst-strfrom tst-strfrom-locale \ +- tst-getrandom tst-atexit tst-at_quick_exit \ +- tst-cxa_atexit tst-on_exit test-atexit-race \ +- test-at_quick_exit-race test-cxa_atexit-race \ +- test-cxa_atexit-race2 \ +- test-on_exit-race test-dlclose-exit-race \ +- tst-makecontext-align test-bz22786 tst-strtod-nan-sign \ +- tst-swapcontext1 tst-setcontext4 tst-setcontext5 \ +- tst-setcontext6 tst-setcontext7 tst-setcontext8 \ +- tst-setcontext9 tst-bz20544 tst-canon-bz26341 \ +- tst-realpath ++tests := bug-fmtmsg1 \ ++ bug-getcontext \ ++ bug-strtod \ ++ bug-strtod2 \ ++ test-a64l \ ++ test-at_quick_exit-race \ ++ test-atexit-race \ ++ test-bz22786 \ ++ test-canon \ ++ test-canon2 \ ++ test-cxa_atexit-race \ ++ test-cxa_atexit-race2 \ ++ test-dlclose-exit-race \ ++ test-on_exit-race \ ++ testdiv \ ++ testmb \ ++ testmb2 \ ++ testrand \ ++ testsort \ ++ tst-at_quick_exit \ ++ tst-atexit \ ++ tst-atof1 \ ++ tst-atof2 \ ++ tst-bsearch \ ++ tst-bz20544 \ ++ tst-canon-bz26341 \ ++ tst-cxa_atexit \ ++ tst-environ \ ++ tst-getrandom \ ++ tst-limits \ ++ tst-makecontext \ ++ tst-makecontext-align \ ++ tst-makecontext2 \ ++ tst-makecontext3 \ ++ tst-on_exit \ ++ tst-qsort \ ++ tst-qsort2 \ ++ tst-quick_exit \ ++ tst-rand48 \ ++ tst-rand48-2 \ ++ tst-random \ ++ tst-random2 \ ++ tst-realpath \ ++ tst-secure-getenv \ ++ tst-setcontext \ ++ tst-setcontext2 \ ++ tst-setcontext3 \ ++ tst-setcontext4 \ ++ tst-setcontext5 \ ++ tst-setcontext6 \ ++ tst-setcontext7 \ ++ tst-setcontext8 \ ++ tst-setcontext9 \ ++ tst-strfmon_l \ ++ tst-strfrom \ ++ tst-strfrom-locale \ ++ tst-strtod \ ++ tst-strtod-nan-locale \ ++ tst-strtod-nan-sign \ ++ tst-strtod-overflow \ ++ tst-strtod-round \ ++ tst-strtod-underflow \ ++ tst-strtod2 \ ++ tst-strtod5 \ ++ tst-strtod6 \ ++ tst-strtol \ ++ tst-strtol-locale \ ++ tst-strtoll \ ++ tst-swapcontext1 \ ++ tst-thread-quick_exit \ ++ tst-tininess \ ++ tst-unsetenv1 \ ++ tst-width \ ++ tst-width-stdint \ ++ tst-xpg-basename + + tests-internal := tst-strtod1i tst-strtod3 tst-strtod4 tst-strtod5i \ + tst-tls-atexit tst-tls-atexit-nodelete +-- +1.8.3.1 + diff --git a/strcmp-delete-align-for-loop_aligned.patch b/strcmp-delete-align-for-loop_aligned.patch new file mode 100644 index 0000000000000000000000000000000000000000..cf5b15a209b25bc27dffa7e9002c277d7b7938c7 --- /dev/null +++ b/strcmp-delete-align-for-loop_aligned.patch @@ -0,0 +1,32 @@ +From 9bbffed83b93f633b272368fc536a4f24e9942e6 Mon Sep 17 00:00:00 2001 +From: Yang Yanchao +Date: Mon, 21 Feb 2022 14:25:25 +0800 +Subject: [PATCH] strcmp: delete align for loop_aligned + +In Kunpeng-920, the performance of strcmp deteriorates only +when the 16 to 23 characters are different.Or the string is +only 16-23 characters.That shows 2 misses per iteration which +means this is a branch predictor issue indeed. +In the preceding scenario, strcmp performance is 300% worse than expected. + +Fortunately, this problem can be solved by modifying the alignment of the functions. +--- + sysdeps/aarch64/strcmp.S | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/sysdeps/aarch64/strcmp.S b/sysdeps/aarch64/strcmp.S +index f225d718..7a048b66 100644 +--- a/sysdeps/aarch64/strcmp.S ++++ b/sysdeps/aarch64/strcmp.S +@@ -71,8 +71,6 @@ ENTRY(strcmp) + b.ne L(misaligned8) + cbnz tmp, L(mutual_align) + +- .p2align 4 +- + L(loop_aligned): + ldr data2, [src1, off2] + ldr data1, [src1], 8 +-- +2.33.0 + diff --git a/sunrpc-Test-case-for-clnt_create-unix-buffer-overflo.patch b/sunrpc-Test-case-for-clnt_create-unix-buffer-overflo.patch new file mode 100644 index 0000000000000000000000000000000000000000..8d2bec498a2353e2feff28843e7db356f10430d1 --- /dev/null +++ b/sunrpc-Test-case-for-clnt_create-unix-buffer-overflo.patch @@ -0,0 +1,89 @@ +From ef972a4c50014a16132b5c75571cfb6b30bef136 Mon Sep 17 00:00:00 2001 +From: Martin Sebor +Date: Mon, 17 Jan 2022 10:21:34 +0100 +Subject: [PATCH] sunrpc: Test case for clnt_create "unix" buffer overflow (bug + 22542) + +Reviewed-by: Siddhesh Poyarekar +--- + sunrpc/Makefile | 5 ++++- + sunrpc/tst-bug22542.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 48 insertions(+), 1 deletion(-) + create mode 100644 sunrpc/tst-bug22542.c + +diff --git a/sunrpc/Makefile b/sunrpc/Makefile +index 9a31fe4..183ef3d 100644 +--- a/sunrpc/Makefile ++++ b/sunrpc/Makefile +@@ -65,7 +65,8 @@ shared-only-routines = $(routines) + endif + + tests = tst-xdrmem tst-xdrmem2 test-rpcent tst-udp-error tst-udp-timeout \ +- tst-udp-nonblocking ++ tst-udp-nonblocking tst-bug22542 ++ + xtests := tst-getmyaddr + + ifeq ($(have-thread-library),yes) +@@ -110,6 +111,8 @@ $(objpfx)tst-udp-nonblocking: $(common-objpfx)linkobj/libc.so + $(objpfx)tst-udp-garbage: \ + $(common-objpfx)linkobj/libc.so $(shared-thread-library) + ++$(objpfx)tst-bug22542: $(common-objpfx)linkobj/libc.so ++ + else # !have-GLIBC_2.31 + + routines = $(routines-for-nss) +diff --git a/sunrpc/tst-bug22542.c b/sunrpc/tst-bug22542.c +new file mode 100644 +index 0000000..d6cd797 +--- /dev/null ++++ b/sunrpc/tst-bug22542.c +@@ -0,0 +1,44 @@ ++/* Test to verify that overlong hostname is rejected by clnt_create ++ and doesn't cause a buffer overflow (bug 22542). ++ ++ Copyright (C) 2022 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ /* Create an arbitrary hostname that's longer than fits in sun_path. */ ++ char name [sizeof ((struct sockaddr_un*)0)->sun_path * 2]; ++ memset (name, 'x', sizeof name - 1); ++ name [sizeof name - 1] = '\0'; ++ ++ errno = 0; ++ CLIENT *clnt = clnt_create (name, 0, 0, "unix"); ++ ++ TEST_VERIFY (clnt == NULL); ++ TEST_COMPARE (errno, EINVAL); ++ return 0; ++} ++ ++#include +-- +1.8.3.1 + diff --git a/support-Add-check-for-TID-zero-in-support_wait_for_t.patch b/support-Add-check-for-TID-zero-in-support_wait_for_t.patch new file mode 100644 index 0000000000000000000000000000000000000000..faccebf116af5b3f2c5d0ac9067d83e50a75e19f --- /dev/null +++ b/support-Add-check-for-TID-zero-in-support_wait_for_t.patch @@ -0,0 +1,42 @@ +From 176c88f5214d8107d330971cbbfbbba5186a111f Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 1 Oct 2021 18:16:41 +0200 +Subject: [PATCH] support: Add check for TID zero in + support_wait_for_thread_exit + +Some kernel versions (observed with kernel 5.14 and earlier) can list +"0" entries in /proc/self/task. This happens when a thread exits +while the task list is being constructed. Treat this entry as not +present, like the proposed kernel patch does: + +[PATCH] procfs: Do not list TID 0 in /proc//task + + +Fixes commit 032d74eaf6179100048a5bf0ce942e97dc8b9a60 ("support: Add +support_wait_for_thread_exit"). + +Reviewed-by: Carlos O'Donell +Tested-by: Carlos O'Donell +--- + support/support_wait_for_thread_exit.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/support/support_wait_for_thread_exit.c b/support/support_wait_for_thread_exit.c +index 658a813..5e3be42 100644 +--- a/support/support_wait_for_thread_exit.c ++++ b/support/support_wait_for_thread_exit.c +@@ -43,7 +43,10 @@ support_wait_for_thread_exit (void) + return; + } + +- if (strcmp (e->d_name, ".") == 0 || strcmp (e->d_name, "..") == 0) ++ /* In some kernels, "0" entries denote a thread that has just ++ exited. */ ++ if (strcmp (e->d_name, ".") == 0 || strcmp (e->d_name, "..") == 0 ++ || strcmp (e->d_name, "0") == 0) + continue; + + int task_tid = atoi (e->d_name); +-- +1.8.3.1 + diff --git a/support-Add-helpers-to-create-paths-longer-than-PATH.patch b/support-Add-helpers-to-create-paths-longer-than-PATH.patch new file mode 100644 index 0000000000000000000000000000000000000000..4d4e73737ee416b1c871b4a1b60aeeafebd60574 --- /dev/null +++ b/support-Add-helpers-to-create-paths-longer-than-PATH.patch @@ -0,0 +1,282 @@ +From 062ff490c1467059f6cd64bb9c3d85f6cc6cf97a Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +Date: Tue, 18 Jan 2022 13:29:36 +0530 +Subject: [PATCH] support: Add helpers to create paths longer than PATH_MAX + +Add new helpers support_create_and_chdir_toolong_temp_directory and +support_chdir_toolong_temp_directory to create and descend into +directory trees longer than PATH_MAX. + +Reviewed-by: Adhemerval Zanella +Signed-off-by: Siddhesh Poyarekar +(cherry picked from commit fb7bff12e81c677a6622f724edd4d4987dd9d971) +--- + support/temp_file.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++---- + support/temp_file.h | 9 +++ + 2 files changed, 160 insertions(+), 10 deletions(-) + +diff --git a/support/temp_file.c b/support/temp_file.c +index c6df641..e41128c 100644 +--- a/support/temp_file.c ++++ b/support/temp_file.c +@@ -1,5 +1,6 @@ + /* Temporary file handling for tests. +- Copyright (C) 1998-2021 Free Software Foundation, Inc. ++ Copyright (C) 1998-2022 Free Software Foundation, Inc. ++ Copyright The GNU Tools Authors. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or +@@ -20,15 +21,17 @@ + some 32-bit platforms. */ + #define _FILE_OFFSET_BITS 64 + ++#include + #include + #include + #include + ++#include + #include + #include + #include + #include +-#include ++#include + + /* List of temporary files. */ + static struct temp_name_list +@@ -36,14 +39,20 @@ static struct temp_name_list + struct temp_name_list *next; + char *name; + pid_t owner; ++ bool toolong; + } *temp_name_list; + + /* Location of the temporary files. Set by the test skeleton via + support_set_test_dir. The string is not be freed. */ + static const char *test_dir = _PATH_TMP; + +-void +-add_temp_file (const char *name) ++/* Name of subdirectories in a too long temporary directory tree. */ ++static char toolong_subdir[NAME_MAX + 1]; ++static bool toolong_initialized; ++static size_t toolong_path_max; ++ ++static void ++add_temp_file_internal (const char *name, bool toolong) + { + struct temp_name_list *newp + = (struct temp_name_list *) xcalloc (sizeof (*newp), 1); +@@ -53,12 +62,19 @@ add_temp_file (const char *name) + newp->name = newname; + newp->next = temp_name_list; + newp->owner = getpid (); ++ newp->toolong = toolong; + temp_name_list = newp; + } + else + free (newp); + } + ++void ++add_temp_file (const char *name) ++{ ++ add_temp_file_internal (name, false); ++} ++ + int + create_temp_file_in_dir (const char *base, const char *dir, char **filename) + { +@@ -90,8 +106,8 @@ create_temp_file (const char *base, char **filename) + return create_temp_file_in_dir (base, test_dir, filename); + } + +-char * +-support_create_temp_directory (const char *base) ++static char * ++create_temp_directory_internal (const char *base, bool toolong) + { + char *path = xasprintf ("%s/%sXXXXXX", test_dir, base); + if (mkdtemp (path) == NULL) +@@ -99,16 +115,132 @@ support_create_temp_directory (const char *base) + printf ("error: mkdtemp (\"%s\"): %m", path); + exit (1); + } +- add_temp_file (path); ++ add_temp_file_internal (path, toolong); + return path; + } + +-/* Helper functions called by the test skeleton follow. */ ++char * ++support_create_temp_directory (const char *base) ++{ ++ return create_temp_directory_internal (base, false); ++} ++ ++static void ++ensure_toolong_initialized (void) ++{ ++ if (!toolong_initialized) ++ FAIL_EXIT1 ("uninitialized toolong directory tree\n"); ++} ++ ++static void ++initialize_toolong (const char *base) ++{ ++ long name_max = pathconf (base, _PC_NAME_MAX); ++ name_max = (name_max < 0 ? 64 ++ : (name_max < sizeof (toolong_subdir) ? name_max ++ : sizeof (toolong_subdir) - 1)); ++ ++ long path_max = pathconf (base, _PC_PATH_MAX); ++ path_max = (path_max < 0 ? 1024 ++ : path_max <= PTRDIFF_MAX ? path_max : PTRDIFF_MAX); ++ ++ /* Sanity check to ensure that the test does not create temporary directories ++ in different filesystems because this API doesn't support it. */ ++ if (toolong_initialized) ++ { ++ if (name_max != strlen (toolong_subdir)) ++ FAIL_UNSUPPORTED ("name_max: Temporary directories in different" ++ " filesystems not supported yet\n"); ++ if (path_max != toolong_path_max) ++ FAIL_UNSUPPORTED ("path_max: Temporary directories in different" ++ " filesystems not supported yet\n"); ++ return; ++ } ++ ++ toolong_path_max = path_max; ++ ++ size_t len = name_max; ++ memset (toolong_subdir, 'X', len); ++ toolong_initialized = true; ++} ++ ++char * ++support_create_and_chdir_toolong_temp_directory (const char *basename) ++{ ++ char *base = create_temp_directory_internal (basename, true); ++ xchdir (base); ++ ++ initialize_toolong (base); ++ ++ size_t sz = strlen (toolong_subdir); ++ ++ /* Create directories and descend into them so that the final path is larger ++ than PATH_MAX. */ ++ for (size_t i = 0; i <= toolong_path_max / sz; i++) ++ { ++ int ret = mkdir (toolong_subdir, S_IRWXU); ++ if (ret != 0 && errno == ENAMETOOLONG) ++ FAIL_UNSUPPORTED ("Filesystem does not support creating too long " ++ "directory trees\n"); ++ else if (ret != 0) ++ FAIL_EXIT1 ("Failed to create directory tree: %m\n"); ++ xchdir (toolong_subdir); ++ } ++ return base; ++} + + void +-support_set_test_dir (const char *path) ++support_chdir_toolong_temp_directory (const char *base) + { +- test_dir = path; ++ ensure_toolong_initialized (); ++ ++ xchdir (base); ++ ++ size_t sz = strlen (toolong_subdir); ++ for (size_t i = 0; i <= toolong_path_max / sz; i++) ++ xchdir (toolong_subdir); ++} ++ ++/* Helper functions called by the test skeleton follow. */ ++ ++static void ++remove_toolong_subdirs (const char *base) ++{ ++ ensure_toolong_initialized (); ++ ++ if (chdir (base) != 0) ++ { ++ printf ("warning: toolong cleanup base failed: chdir (\"%s\"): %m\n", ++ base); ++ return; ++ } ++ ++ /* Descend. */ ++ int levels = 0; ++ size_t sz = strlen (toolong_subdir); ++ for (levels = 0; levels <= toolong_path_max / sz; levels++) ++ if (chdir (toolong_subdir) != 0) ++ { ++ printf ("warning: toolong cleanup failed: chdir (\"%s\"): %m\n", ++ toolong_subdir); ++ break; ++ } ++ ++ /* Ascend and remove. */ ++ while (--levels >= 0) ++ { ++ if (chdir ("..") != 0) ++ { ++ printf ("warning: toolong cleanup failed: chdir (\"..\"): %m\n"); ++ return; ++ } ++ if (remove (toolong_subdir) != 0) ++ { ++ printf ("warning: could not remove subdirectory: %s: %m\n", ++ toolong_subdir); ++ return; ++ } ++ } + } + + void +@@ -123,6 +255,9 @@ support_delete_temp_files (void) + around, to prevent PID reuse.) */ + if (temp_name_list->owner == pid) + { ++ if (temp_name_list->toolong) ++ remove_toolong_subdirs (temp_name_list->name); ++ + if (remove (temp_name_list->name) != 0) + printf ("warning: could not remove temporary file: %s: %m\n", + temp_name_list->name); +@@ -147,3 +282,9 @@ support_print_temp_files (FILE *f) + fprintf (f, ")\n"); + } + } ++ ++void ++support_set_test_dir (const char *path) ++{ ++ test_dir = path; ++} +diff --git a/support/temp_file.h b/support/temp_file.h +index f3a7fb6..a22964c 100644 +--- a/support/temp_file.h ++++ b/support/temp_file.h +@@ -44,6 +44,15 @@ int create_temp_file_in_dir (const char *base, const char *dir, + returns. The caller should free this string. */ + char *support_create_temp_directory (const char *base); + ++/* Create a temporary directory tree that is longer than PATH_MAX and schedule ++ it for deletion. BASENAME is used as a prefix for the unique directory ++ name, which the function returns. The caller should free this string. */ ++char *support_create_and_chdir_toolong_temp_directory (const char *basename); ++ ++/* Change into the innermost directory of the directory tree BASE, which was ++ created using support_create_and_chdir_toolong_temp_directory. */ ++void support_chdir_toolong_temp_directory (const char *base); ++ + __END_DECLS + + #endif /* SUPPORT_TEMP_FILE_H */ +-- +1.8.3.1 + diff --git a/support-Add-support_open_dev_null_range.patch b/support-Add-support_open_dev_null_range.patch new file mode 100644 index 0000000000000000000000000000000000000000..0b78f8cc6e23fb1d755fed2f41323697abd6025d --- /dev/null +++ b/support-Add-support_open_dev_null_range.patch @@ -0,0 +1,363 @@ +From e814f4b04ee413a7bb3dfa43e74c8fb4abf58359 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Tue, 24 Aug 2021 16:12:24 -0300 +Subject: [PATCH] support: Add support_open_dev_null_range + +It returns a range of file descriptor referring to the '/dev/null' +pathname. The function takes care of restarting the open range +if a file descriptor is found within the specified range and +also increases RLIMIT_NOFILE if required. + +Checked on x86_64-linux-gnu. +--- + support/Makefile | 2 + + support/support-open-dev-null-range.c | 134 ++++++++++++++++++++++++++ + support/support.h | 8 ++ + support/tst-support-open-dev-null-range.c | 155 ++++++++++++++++++++++++++++++ + 4 files changed, 299 insertions(+) + create mode 100644 support/support-open-dev-null-range.c + create mode 100644 support/tst-support-open-dev-null-range.c + +diff --git a/support/Makefile b/support/Makefile +index a462781..6332e7b 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -66,6 +66,7 @@ libsupport-routines = \ + support_path_support_time64 \ + support_process_state \ + support_ptrace \ ++ support-open-dev-null-range \ + support_openpty \ + support_paths \ + support_quote_blob \ +@@ -264,6 +265,7 @@ tests = \ + tst-support_capture_subprocess \ + tst-support_descriptors \ + tst-support_format_dns_packet \ ++ tst-support-open-dev-null-range \ + tst-support-process_state \ + tst-support_quote_blob \ + tst-support_quote_string \ +diff --git a/support/support-open-dev-null-range.c b/support/support-open-dev-null-range.c +new file mode 100644 +index 0000000..80d9dba +--- /dev/null ++++ b/support/support-open-dev-null-range.c +@@ -0,0 +1,134 @@ ++/* Return a range of open file descriptors. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void ++increase_nofile (void) ++{ ++ struct rlimit rl; ++ if (getrlimit (RLIMIT_NOFILE, &rl) == -1) ++ FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m"); ++ ++ rl.rlim_cur += 128; ++ ++ if (setrlimit (RLIMIT_NOFILE, &rl) == 1) ++ FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m"); ++} ++ ++static int ++open_dev_null (int flags, mode_t mode) ++{ ++ int fd = open64 ("/dev/null", flags, mode); ++ if (fd > 0) ++ return fd; ++ ++ if (fd < 0 && errno != EMFILE) ++ FAIL_EXIT1 ("open64 (\"/dev/null\", 0x%x, 0%o): %m", flags, mode); ++ ++ increase_nofile (); ++ ++ return xopen ("/dev/null", flags, mode); ++} ++ ++struct range ++{ ++ int lowfd; ++ size_t len; ++}; ++ ++struct range_list ++{ ++ size_t total; ++ size_t used; ++ struct range *ranges; ++}; ++ ++static void ++range_init (struct range_list *r) ++{ ++ r->total = 8; ++ r->used = 0; ++ r->ranges = xmalloc (r->total * sizeof (struct range)); ++} ++ ++static void ++range_add (struct range_list *r, int lowfd, size_t len) ++{ ++ if (r->used == r->total) ++ { ++ r->total *= 2; ++ r->ranges = xrealloc (r->ranges, r->total * sizeof (struct range)); ++ } ++ r->ranges[r->used].lowfd = lowfd; ++ r->ranges[r->used].len = len; ++ r->used++; ++} ++ ++static void ++range_close (struct range_list *r) ++{ ++ for (size_t i = 0; i < r->used; i++) ++ { ++ int minfd = r->ranges[i].lowfd; ++ int maxfd = r->ranges[i].lowfd + r->ranges[i].len; ++ for (int fd = minfd; fd < maxfd; fd++) ++ xclose (fd); ++ } ++ free (r->ranges); ++} ++ ++int ++support_open_dev_null_range (int num, int flags, mode_t mode) ++{ ++ /* We keep track of the ranges that hit an already opened descriptor, so ++ we close them after we get a working range. */ ++ struct range_list rl; ++ range_init (&rl); ++ ++ int lowfd = open_dev_null (flags, mode); ++ int prevfd = lowfd; ++ while (true) ++ { ++ int i = 1; ++ for (; i < num; i++) ++ { ++ int fd = open_dev_null (flags, mode); ++ if (fd != lowfd + i) ++ { ++ range_add (&rl, lowfd, prevfd - lowfd + 1); ++ ++ prevfd = lowfd = fd; ++ break; ++ } ++ prevfd = fd; ++ } ++ if (i == num) ++ break; ++ } ++ ++ range_close (&rl); ++ ++ return lowfd; ++} +diff --git a/support/support.h b/support/support.h +index 834dba9..e6911e1 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -193,6 +193,14 @@ struct support_stack support_stack_alloc (size_t size); + /* Deallocate the STACK. */ + void support_stack_free (struct support_stack *stack); + ++ ++/* Create a range of NUM opened '/dev/null' file descriptors using FLAGS and ++ MODE. The function takes care of restarting the open range if a file ++ descriptor is found within the specified range and also increases ++ RLIMIT_NOFILE if required. ++ The returned value is the lowest file descriptor number. */ ++int support_open_dev_null_range (int num, int flags, mode_t mode); ++ + __END_DECLS + + #endif /* SUPPORT_H */ +diff --git a/support/tst-support-open-dev-null-range.c b/support/tst-support-open-dev-null-range.c +new file mode 100644 +index 0000000..8e29def +--- /dev/null ++++ b/support/tst-support-open-dev-null-range.c +@@ -0,0 +1,155 @@ ++/* Tests for support_open_dev_null_range. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef PATH_MAX ++# define PATH_MAX 1024 ++#endif ++ ++#include ++ ++static void ++check_path (int fd) ++{ ++ char *proc_fd_path = xasprintf ("/proc/self/fd/%d", fd); ++ char file_path[PATH_MAX]; ++ ssize_t file_path_length ++ = readlink (proc_fd_path, file_path, sizeof (file_path)); ++ free (proc_fd_path); ++ if (file_path_length < 0) ++ FAIL_EXIT1 ("readlink (%s, %p, %zu)", proc_fd_path, file_path, ++ sizeof (file_path)); ++ file_path[file_path_length] = '\0'; ++ TEST_COMPARE_STRING (file_path, "/dev/null"); ++} ++ ++static int ++number_of_opened_files (void) ++{ ++ DIR *fds = opendir ("/proc/self/fd"); ++ if (fds == NULL) ++ FAIL_EXIT1 ("opendir (\"/proc/self/fd\"): %m"); ++ ++ int r = 0; ++ while (true) ++ { ++ errno = 0; ++ struct dirent64 *e = readdir64 (fds); ++ if (e == NULL) ++ { ++ if (errno != 0) ++ FAIL_EXIT1 ("readdir: %m"); ++ break; ++ } ++ ++ if (e->d_name[0] == '.') ++ continue; ++ ++ char *endptr; ++ long int fd = strtol (e->d_name, &endptr, 10); ++ if (*endptr != '\0' || fd < 0 || fd > INT_MAX) ++ FAIL_EXIT1 ("readdir: invalid file descriptor name: /proc/self/fd/%s", ++ e->d_name); ++ ++ /* Skip the descriptor which is used to enumerate the ++ descriptors. */ ++ if (fd == dirfd (fds)) ++ continue; ++ ++ r = r + 1; ++ } ++ ++ closedir (fds); ++ ++ return r; ++} ++ ++static int ++do_test (void) ++{ ++ const int nfds1 = 8; ++ int lowfd = support_open_dev_null_range (nfds1, O_RDONLY, 0600); ++ for (int i = 0; i < nfds1; i++) ++ { ++ TEST_VERIFY (fcntl (lowfd + i, F_GETFL) > -1); ++ check_path (lowfd + i); ++ } ++ ++ /* create some gaps. */ ++ xclose (lowfd + 1); ++ xclose (lowfd + 5); ++ xclose (lowfd + 6); ++ ++ const int nfds2 = 16; ++ int lowfd2 = support_open_dev_null_range (nfds2, O_RDONLY, 0600); ++ for (int i = 0; i < nfds2; i++) ++ { ++ TEST_VERIFY (fcntl (lowfd2 + i, F_GETFL) > -1); ++ check_path (lowfd2 + i); ++ } ++ ++ /* Decrease the maximum number of files. */ ++ { ++ struct rlimit rl; ++ if (getrlimit (RLIMIT_NOFILE, &rl) == -1) ++ FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m"); ++ ++ rl.rlim_cur = number_of_opened_files (); ++ ++ if (setrlimit (RLIMIT_NOFILE, &rl) == 1) ++ FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m"); ++ } ++ ++ const int nfds3 = 16; ++ int lowfd3 = support_open_dev_null_range (nfds3, O_RDONLY, 0600); ++ for (int i = 0; i < nfds3; i++) ++ { ++ TEST_VERIFY (fcntl (lowfd3 + i, F_GETFL) > -1); ++ check_path (lowfd3 + i); ++ } ++ ++ /* create a lot of gaps to trigger the range extension. */ ++ xclose (lowfd3 + 1); ++ xclose (lowfd3 + 3); ++ xclose (lowfd3 + 5); ++ xclose (lowfd3 + 7); ++ xclose (lowfd3 + 9); ++ xclose (lowfd3 + 11); ++ xclose (lowfd3 + 13); ++ ++ const int nfds4 = 16; ++ int lowfd4 = support_open_dev_null_range (nfds4, O_RDONLY, 0600); ++ for (int i = 0; i < nfds4; i++) ++ { ++ TEST_VERIFY (fcntl (lowfd4 + i, F_GETFL) > -1); ++ check_path (lowfd4 + i); ++ } ++ ++ return 0; ++} ++ ++#include +-- +1.8.3.1 + diff --git a/support-Add-support_socket_so_timestamp_time64.patch b/support-Add-support_socket_so_timestamp_time64.patch new file mode 100644 index 0000000000000000000000000000000000000000..e6f9922075f9f47e37aa6c7f045988f0d846d76d --- /dev/null +++ b/support-Add-support_socket_so_timestamp_time64.patch @@ -0,0 +1,103 @@ +From e09e7b1492b2d5c2f68ddf81f8f58e093dd4df6d Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Mon, 13 Dec 2021 11:36:42 -0300 +Subject: [PATCH] support: Add support_socket_so_timestamp_time64 + +Check if the socket support 64-bit network packages timestamps +(SO_TIMESTAMP and SO_TIMESTAMPNS). This will be used on recvmsg +and recvmmsg tests to check if the timestamp should be generated. + +Reviewed-by: Florian Weimer + +(cherry picked from 38bc0f4e78934aab455b31af05cefcbf3c22bece) +--- + support/Makefile | 1 + + support/support.h | 4 ++ + support/support_socket_so_timestamp_time64.c | 48 ++++++++++++++++++++ + 3 files changed, 53 insertions(+) + create mode 100644 support/support_socket_so_timestamp_time64.c + +diff --git a/support/Makefile b/support/Makefile +index 2a0731796f..724ae6d712 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -78,6 +78,7 @@ libsupport-routines = \ + support_set_small_thread_stack_size \ + support_shared_allocate \ + support_small_stack_thread_attribute \ ++ support_socket_so_timestamp_time64 \ + support_stat_nanoseconds \ + support_subprocess \ + support_test_compare_blob \ +diff --git a/support/support.h b/support/support.h +index c219e0d9d1..309be85b09 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -164,6 +164,10 @@ extern bool support_select_modifies_timeout (void); + tv_usec larger than 1000000. */ + extern bool support_select_normalizes_timeout (void); + ++/* Return true if socket FD supports 64-bit timestamps with the SOL_SOCKET ++ and SO_TIMESTAMP/SO_TIMESTAMPNS. */ ++extern bool support_socket_so_timestamp_time64 (int fd); ++ + /* Create a timer that trigger after SEC seconds and NSEC nanoseconds. If + REPEAT is true the timer will repeat indefinitely. If CALLBACK is not + NULL, the function will be called when the timer expires; otherwise a +diff --git a/support/support_socket_so_timestamp_time64.c b/support/support_socket_so_timestamp_time64.c +new file mode 100644 +index 0000000000..54bf3f4272 +--- /dev/null ++++ b/support/support_socket_so_timestamp_time64.c +@@ -0,0 +1,48 @@ ++/* Return whether socket supports 64-bit timestamps. ++ Copyright (C) 2022 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#ifdef __linux__ ++# include ++#endif ++ ++bool ++support_socket_so_timestamp_time64 (int fd) ++{ ++#ifdef __linux__ ++# if __LINUX_KERNEL_VERSION >= 0x050100 \ ++ || __WORDSIZE == 64 \ ++ || (defined __SYSCALL_WORDSIZE && __SYSCALL_WORDSIZE == 64) ++ return true; ++# else ++ int level = SOL_SOCKET; ++ int optname = COMPAT_SO_TIMESTAMP_NEW; ++ int optval; ++ socklen_t len = sizeof (optval); ++ ++ int r = syscall (__NR_getsockopt, fd, level, optname, &optval, &len); ++ return r != -1; ++# endif ++#else ++ return false; ++#endif ++} +-- +2.27.0 + diff --git a/support-Add-support_wait_for_thread_exit.patch b/support-Add-support_wait_for_thread_exit.patch new file mode 100644 index 0000000000000000000000000000000000000000..97ca806ec6d13510d7e68df0719cb9b8de86437d --- /dev/null +++ b/support-Add-support_wait_for_thread_exit.patch @@ -0,0 +1,124 @@ +From 032d74eaf6179100048a5bf0ce942e97dc8b9a60 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Mon, 30 Aug 2021 13:43:56 +0200 +Subject: [PATCH] support: Add support_wait_for_thread_exit + +--- + support/Makefile | 3 +- + support/support.h | 4 ++ + support/support_wait_for_thread_exit.c | 72 ++++++++++++++++++++++++++++++++++ + 3 files changed, 78 insertions(+), 1 deletion(-) + create mode 100644 support/support_wait_for_thread_exit.c + +diff --git a/support/Makefile b/support/Makefile +index 6332e7b..2a07317 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -83,9 +83,10 @@ libsupport-routines = \ + support_test_compare_blob \ + support_test_compare_failure \ + support_test_compare_string \ +- support_write_file_string \ + support_test_main \ + support_test_verify_impl \ ++ support_wait_for_thread_exit \ ++ support_write_file_string \ + temp_file \ + timespec \ + timespec-time64 \ +diff --git a/support/support.h b/support/support.h +index e6911e1..c219e0d 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -174,6 +174,10 @@ timer_t support_create_timer (uint64_t sec, long int nsec, bool repeat, + /* Disable the timer TIMER. */ + void support_delete_timer (timer_t timer); + ++/* Wait until all threads except the current thread have exited (as ++ far as the kernel is concerned). */ ++void support_wait_for_thread_exit (void); ++ + struct support_stack + { + void *stack; +diff --git a/support/support_wait_for_thread_exit.c b/support/support_wait_for_thread_exit.c +new file mode 100644 +index 0000000..658a813 +--- /dev/null ++++ b/support/support_wait_for_thread_exit.c +@@ -0,0 +1,72 @@ ++/* Wait until all threads except the current thread has exited. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++void ++support_wait_for_thread_exit (void) ++{ ++#ifdef __linux__ ++ DIR *proc_self_task = opendir ("/proc/self/task"); ++ TEST_VERIFY_EXIT (proc_self_task != NULL); ++ ++ while (true) ++ { ++ errno = 0; ++ struct dirent *e = readdir (proc_self_task); ++ if (e == NULL && errno != 0) ++ FAIL_EXIT1 ("readdir: %m"); ++ if (e == NULL) ++ { ++ /* Only the main thread remains. Testing may continue. */ ++ closedir (proc_self_task); ++ return; ++ } ++ ++ if (strcmp (e->d_name, ".") == 0 || strcmp (e->d_name, "..") == 0) ++ continue; ++ ++ int task_tid = atoi (e->d_name); ++ if (task_tid <= 0) ++ FAIL_EXIT1 ("Invalid /proc/self/task entry: %s", e->d_name); ++ ++ if (task_tid == gettid ()) ++ /* The current thread. Keep scanning for other ++ threads. */ ++ continue; ++ ++ /* task_tid does not refer to this thread here, i.e., there is ++ another running thread. */ ++ ++ /* Small timeout to give the thread a chance to exit. */ ++ usleep (50 * 1000); ++ ++ /* Start scanning the directory from the start. */ ++ rewinddir (proc_self_task); ++ } ++#else ++ /* Use a large timeout because we cannot verify that the thread has ++ exited. */ ++ usleep (5 * 1000 * 1000); ++#endif ++} +-- +1.8.3.1 + diff --git a/support-Also-return-fd-when-it-is-0.patch b/support-Also-return-fd-when-it-is-0.patch new file mode 100644 index 0000000000000000000000000000000000000000..150b4c3fd6ab40afdafd36afbaaf6f873a397bfa --- /dev/null +++ b/support-Also-return-fd-when-it-is-0.patch @@ -0,0 +1,45 @@ +From 27b6edbb090f736b101f569620d8ad0e7217ddf8 Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +Date: Wed, 6 Oct 2021 21:48:35 +0530 +Subject: [PATCH] support: Also return fd when it is 0 + +The fd validity check in open_dev_null checks if fd > 0, which would +lead to a leaked fd if it is == 0. + +Signed-off-by: Siddhesh Poyarekar +Reviewed-by: Adhemerval Zanella +--- + support/support-open-dev-null-range.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/support/support-open-dev-null-range.c b/support/support-open-dev-null-range.c +index 80d9dba..66a8504 100644 +--- a/support/support-open-dev-null-range.c ++++ b/support/support-open-dev-null-range.c +@@ -40,16 +40,16 @@ increase_nofile (void) + static int + open_dev_null (int flags, mode_t mode) + { +- int fd = open64 ("/dev/null", flags, mode); +- if (fd > 0) +- return fd; ++ int fd = open64 ("/dev/null", flags, mode); ++ if (fd >= 0) ++ return fd; + +- if (fd < 0 && errno != EMFILE) +- FAIL_EXIT1 ("open64 (\"/dev/null\", 0x%x, 0%o): %m", flags, mode); ++ if (fd < 0 && errno != EMFILE) ++ FAIL_EXIT1 ("open64 (\"/dev/null\", 0x%x, 0%o): %m", flags, mode); + +- increase_nofile (); ++ increase_nofile (); + +- return xopen ("/dev/null", flags, mode); ++ return xopen ("/dev/null", flags, mode); + } + + struct range +-- +1.8.3.1 + diff --git a/testsuite_whitelist b/testsuite_whitelist new file mode 100644 index 0000000000000000000000000000000000000000..b99f3d554d1d930300d3934242b229ddec8d7ef9 --- /dev/null +++ b/testsuite_whitelist @@ -0,0 +1,129 @@ +# USAGE: +# If it's a generic error: +# testsuite +# If the test case fails on part of the architecture: +# testsuite:arch1,arch2 + +# These test cases failed due to gcc_secure +conform/ISO/setjmp.h/conform +conform/ISO/stdlib.h/conform +conform/ISO/stdlib.h/linknamespace +conform/ISO/string.h/conform +conform/ISO11/setjmp.h/conform +conform/ISO11/stdio.h/conform +conform/ISO11/stdlib.h/conform +conform/ISO11/stdlib.h/linknamespace +conform/ISO11/string.h/conform +conform/ISO11/wchar.h/conform +conform/ISO99/setjmp.h/conform +conform/ISO99/stdio.h/conform +conform/ISO99/stdlib.h/conform +conform/ISO99/stdlib.h/linknamespace +conform/ISO99/string.h/conform +conform/ISO99/wchar.h/conform +conform/POSIX/stdlib.h/conform +conform/POSIX/stdlib.h/linknamespace +conform/POSIX/string.h/conform +conform/POSIX2008/fcntl.h/conform +conform/POSIX2008/mqueue.h/conform +conform/POSIX2008/stdio.h/conform +conform/POSIX2008/stdlib.h/conform +conform/POSIX2008/stdlib.h/linknamespace +conform/POSIX2008/wchar.h/conform +conform/UNIX98/stdlib.h/conform +conform/UNIX98/string.h/conform +conform/UNIX98/unistd.h/conform +conform/UNIX98/unistd.h/linknamespace +conform/UNIX98/wchar.h/conform +conform/XOPEN2K/fcntl.h/conform +conform/XOPEN2K/mqueue.h/conform +conform/XOPEN2K/stdio.h/conform +conform/XOPEN2K/stdlib.h/conform +conform/XOPEN2K/string.h/conform +conform/XOPEN2K/syslog.h/conform +conform/XOPEN2K/unistd.h/conform +conform/XOPEN2K/unistd.h/linknamespace +conform/XOPEN2K/wchar.h/conform +conform/XOPEN2K8/fcntl.h/conform +conform/XOPEN2K8/mqueue.h/conform +conform/XOPEN2K8/stdio.h/conform +conform/XOPEN2K8/stdlib.h/conform +conform/XOPEN2K8/syslog.h/conform +conform/XOPEN2K8/unistd.h/conform +conform/XOPEN2K8/unistd.h/linknamespace +conform/XOPEN2K8/wchar.h/conform +conform/XPG4/stdlib.h/conform +conform/XPG4/stdlib.h/linknamespace +conform/XPG4/string.h/conform +conform/XPG4/unistd.h/conform +conform/XPG42/stdlib.h/conform +conform/XPG42/string.h/conform +conform/XPG42/unistd.h/conform +elf/circleload1 +elf/constload1 +elf/dblload +elf/dblunload +elf/ifuncmain6pie:x86_64 +elf/lateglobal +elf/reldep6 +elf/resolvfail +elf/tst-global1 +elf/tst-tls20 +nptl/tst-execstack + +# GCC no longer implements +conform/UNIX98/varargs.h/conform +conform/UNIX98/varargs.h/linknamespace +conform/XPG4/varargs.h/conform +conform/XPG4/varargs.h/linknamespace +conform/XPG42/varargs.h/conform +conform/XPG42/varargs.h/linknamespace + +# These cases depend on gdbm-devel +conform/UNIX98/ndbm.h/conform +conform/UNIX98/ndbm.h/linknamespace +conform/XOPEN2K/ndbm.h/conform +conform/XOPEN2K/ndbm.h/linknamespace +conform/XOPEN2K8/ndbm.h/conform +conform/XOPEN2K8/ndbm.h/linknamespace +conform/XPG42/ndbm.h/conform +conform/XPG42/ndbm.h/linknamespace + +# Test whether the date/time is correct under different +# language libraries, use case problems, and see that +# the compiled language library itself has no errors +# https://sourceware.org/bugzilla/show_bug.cgi?id=23164 +localedata/tst-langinfo-newlocale-static + +# The use case itself passed but because +# test-xfail-tst-protected1a/test-xfail-tst-protected1b was added +elf/tst-protected1a +elf/tst-protected1b + +# the test case is due to check whether a macro is defined +# in the header files. As GLIBC evolves, the position of the +# macro changes, causing the use case to fail +posix/annexc + +# Check whether sys/mman.h is consistent with linux/mman.h. +# kernel has a self-developed macro that does not require glibc adaptation +# https://gitee.com/src-openeuler/kernel/issues/I4BZ9T?from=project-issue +misc/tst-mman-consts + +# It need to build GliBC on a platform that supports CET +elf/check-cet:x86_64 + +# Add the tst-nss-files-hosts-long.root/etc/hosts of glibc to +# the /etc/hosts directory of the system, and then run sucess +nss/tst-nss-files-hosts-long + +# The test case fails due to OBS machine restrictions which can be passed locally. +elf/tst-debug1:aarch64 + +# This test case often fails in CI which is the high-pressure environment. +# No better solution is available. This test case is shielded. +rt/tst-cpuclock2 + +# These testcase fails because rseq is disabled by default +misc/tst-rseq-nptl +misc/tst-rseq diff --git a/time-Fix-overflow-itimer-tests-on-32-bit-systems.patch b/time-Fix-overflow-itimer-tests-on-32-bit-systems.patch new file mode 100644 index 0000000000000000000000000000000000000000..939e816cf880d4372574433d98b396997fa99ec1 --- /dev/null +++ b/time-Fix-overflow-itimer-tests-on-32-bit-systems.patch @@ -0,0 +1,90 @@ +From 6e8a0aac2f883a23efb1683b120499138f9e6021 Mon Sep 17 00:00:00 2001 +From: Stafford Horne +Date: Mon, 7 Jun 2021 22:10:19 +0900 +Subject: [PATCH] time: Fix overflow itimer tests on 32-bit systems + +On the port of OpenRISC I am working on and it appears the rv32 port +we have sets __TIMESIZE == 64 && __WORDSIZE == 32. This causes the +size of time_t to be 8 bytes, but the tv_sec in the kernel is still 32-bit +causing truncation. + +The truncations are unavoidable on these systems so skip the +testing/failures by guarding with __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64. + +Also, futher in the tests and in other parts of code checking for time_t +overflow does not work on 32-bit systems when time_t is 64-bit. As +suggested by Adhemerval, update the in_time_t_range function to assume +32-bits by using int32_t. + +This also brings in the header for stdint.h so we can update other +usages of __int32_t to int32_t as suggested by Adhemerval. + +Reviewed-by: Adhemerval Zanella +--- + include/time.h | 10 ++++++---- + time/tst-itimer.c | 4 ++-- + 2 files changed, 8 insertions(+), 6 deletions(-) + +diff --git a/include/time.h b/include/time.h +index 22b29ca..127347e 100644 +--- a/include/time.h ++++ b/include/time.h +@@ -11,6 +11,7 @@ + # include + # include + # include ++# include + + extern __typeof (strftime_l) __strftime_l; + libc_hidden_proto (__strftime_l) +@@ -342,11 +343,12 @@ libc_hidden_proto (__time64) + actual clock ID. */ + #define CLOCK_IDFIELD_SIZE 3 + +-/* Check whether T fits in time_t. */ ++/* Check whether T fits in int32_t, assume all usages are for ++ sizeof(time_t) == 32. */ + static inline bool + in_time_t_range (__time64_t t) + { +- time_t s = t; ++ int32_t s = t; + return s == t; + } + +@@ -453,8 +455,8 @@ timespec64_to_timeval64 (const struct __timespec64 ts64) + and suseconds_t. */ + struct __timeval32 + { +- __int32_t tv_sec; /* Seconds. */ +- __int32_t tv_usec; /* Microseconds. */ ++ int32_t tv_sec; /* Seconds. */ ++ int32_t tv_usec; /* Microseconds. */ + }; + + /* Conversion functions for converting to/from __timeval32 */ +diff --git a/time/tst-itimer.c b/time/tst-itimer.c +index 929c2b7..bd7d7af 100644 +--- a/time/tst-itimer.c ++++ b/time/tst-itimer.c +@@ -100,7 +100,7 @@ do_test (void) + + /* Linux does not provide 64 bit time_t support for getitimer and + setitimer on architectures with 32 bit time_t support. */ +- if (sizeof (__time_t) == 8) ++ if (__KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64) + { + TEST_COMPARE (setitimer (timers[i], &it, NULL), 0); + TEST_COMPARE (setitimer (timers[i], &(struct itimerval) { 0 }, +@@ -131,7 +131,7 @@ do_test (void) + it.it_interval.tv_usec = 20; + it.it_value.tv_sec = 30; + it.it_value.tv_usec = 40; +- if (sizeof (__time_t) == 8) ++ if (__KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64) + { + TEST_COMPARE (setitimer (timers[i], &it, NULL), 0); + +-- +1.8.3.1 + diff --git a/timex-Use-64-bit-fields-on-32-bit-TIMESIZE-64-system.patch b/timex-Use-64-bit-fields-on-32-bit-TIMESIZE-64-system.patch new file mode 100644 index 0000000000000000000000000000000000000000..3c6d72b163613c81bf3ba5a8f978eb874e411cab --- /dev/null +++ b/timex-Use-64-bit-fields-on-32-bit-TIMESIZE-64-system.patch @@ -0,0 +1,45 @@ +From 1d550265a75b412cea4889a50b101395f6a8e025 Mon Sep 17 00:00:00 2001 +From: Stafford Horne +Date: Fri, 15 Oct 2021 06:17:41 +0900 +Subject: [PATCH] timex: Use 64-bit fields on 32-bit TIMESIZE=64 systems (BZ + #28469) + +This was found when testing the OpenRISC port I am working on. These +two tests fail with SIGSEGV: + + FAIL: misc/tst-ntp_gettime + FAIL: misc/tst-ntp_gettimex + +This was found to be due to the kernel overwriting the stack space +allocated by the timex structure. The reason for the overwrite being +that the kernel timex has 64-bit fields and user space code only +allocates enough stack space for timex with 32-bit fields. + +On 32-bit systems with TIMESIZE=64 __USE_TIME_BITS64 is not defined. +This causes the timex structure to use 32-bit fields with type +__syscall_slong_t. + +This patch adjusts the ifdef condition to allow 32-bit systems with +TIMESIZE=64 to use the 64-bit long long timex definition. + +Reviewed-by: Adhemerval Zanella +--- + sysdeps/unix/sysv/linux/bits/timex.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sysdeps/unix/sysv/linux/bits/timex.h b/sysdeps/unix/sysv/linux/bits/timex.h +index ee37694..4a5db6d 100644 +--- a/sysdeps/unix/sysv/linux/bits/timex.h ++++ b/sysdeps/unix/sysv/linux/bits/timex.h +@@ -25,7 +25,7 @@ + + struct timex + { +-# ifdef __USE_TIME_BITS64 ++# if defined __USE_TIME_BITS64 || (__TIMESIZE == 64 && __WORDSIZE == 32) + unsigned int modes; /* mode selector */ + int :32; /* pad */ + long long offset; /* time offset (usec) */ +-- +1.8.3.1 + diff --git a/timezone-handle-truncated-timezones-from-tzcode-2021.patch b/timezone-handle-truncated-timezones-from-tzcode-2021.patch new file mode 100644 index 0000000000000000000000000000000000000000..10ef9e8dc746a9ccfc237095750bda0bb88c6bae --- /dev/null +++ b/timezone-handle-truncated-timezones-from-tzcode-2021.patch @@ -0,0 +1,57 @@ +From c36f64aa6dff13b12a1e03a185e75a50fa9f6a4c Mon Sep 17 00:00:00 2001 +From: Hans-Peter Nilsson +Date: Fri, 17 Dec 2021 21:38:00 +0100 +Subject: [PATCH] timezone: handle truncated timezones from tzcode-2021d and + later (BZ #28707) + +When using a timezone file with a truncated starting time, +generated by the zic in IANA tzcode-2021d a.k.a. tzlib-2021d +(also in tzlib-2021e; current as of this writing), glibc +asserts in __tzfile_read (on e.g. tzset() for this file) and +you may find lines matching "tzfile.c:435: __tzfile_read: +Assertion `num_types == 1' failed" in your syslog. + +One example of such a file is the tzfile for Asuncion +generated by tzlib-2021e as follows, using the tzlib-2021e zic: +"zic -d DEST -r @1546300800 -L /dev/null -b slim +SOURCE/southamerica". Note that in its type 2 header, it has +two entries in its "time-types" array (types), but only one +entry in its "transition types" array (type_idxs). + +This is valid and expected already in the published RFC8536, and +not even frowned upon: "Local time for timestamps before the +first transition is specified by the first time type (time type +0)" ... "every nonzero local time type index SHOULD appear at +least once in the transition type array". Note the "nonzero ... +index". Until the 2021d zic, index 0 has been shared by the +first valid transition but with 2021d it's separate, set apart +as a placeholder and only "implicitly" indexed. (A draft update +of the RFC mandates that the entry at index 0 is a placeholder +in this case, hence can no longer be shared.) + + * time/tzfile.c (__tzfile_read): Don't assert when no transitions + are found. + +Co-authored-by: Christopher Wong +--- + time/tzfile.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/time/tzfile.c b/time/tzfile.c +index 190a777..8668392 100644 +--- a/time/tzfile.c ++++ b/time/tzfile.c +@@ -431,8 +431,8 @@ __tzfile_read (const char *file, size_t extra, char **extrap) + if (__tzname[0] == NULL) + { + /* This should only happen if there are no transition rules. +- In this case there should be only one single type. */ +- assert (num_types == 1); ++ In this case there's usually only one single type, unless ++ e.g. the data file has a truncated time-range. */ + __tzname[0] = __tzstring (zone_names); + } + if (__tzname[1] == NULL) +-- +1.8.3.1 + diff --git a/timezone-test-case-for-BZ-28707.patch b/timezone-test-case-for-BZ-28707.patch new file mode 100644 index 0000000000000000000000000000000000000000..2b0b3fee6c498e1427298b34d2dc12740c3e13c5 --- /dev/null +++ b/timezone-test-case-for-BZ-28707.patch @@ -0,0 +1,138 @@ +From ebe899af0dc3215159a9c896ac6f35b72a18cb6e Mon Sep 17 00:00:00 2001 +From: Hans-Peter Nilsson +Date: Fri, 17 Dec 2021 21:45:54 +0100 +Subject: [PATCH] timezone: test-case for BZ #28707 + +This test-case is the tzfile for Asuncion generated by +tzlib-2021e as follows, using the tzlib-2021e zic: "zic -d +DEST -r @1546300800 -L /dev/null -b slim +SOURCE/southamerica". Note that in its type 2 header, it +has two entries in its "time-types" array (types), but only +one entry in its "transition types" array (type_idxs). + + * timezone/Makefile, timezone/tst-pr28707.c, + timezone/testdata/gen-XT5.sh: New test. + +Co-authored-by: Christopher Wong +--- + timezone/Makefile | 8 +++++++- + timezone/testdata/gen-XT5.sh | 16 +++++++++++++++ + timezone/tst-bz28707.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 69 insertions(+), 1 deletion(-) + create mode 100755 timezone/testdata/gen-XT5.sh + create mode 100644 timezone/tst-bz28707.c + +diff --git a/timezone/Makefile b/timezone/Makefile +index c624a18..f091663 100644 +--- a/timezone/Makefile ++++ b/timezone/Makefile +@@ -23,7 +23,7 @@ subdir := timezone + include ../Makeconfig + + others := zdump zic +-tests := test-tz tst-timezone tst-tzset ++tests := test-tz tst-timezone tst-tzset tst-bz28707 + + generated-dirs += testdata + +@@ -85,10 +85,12 @@ $(objpfx)tst-timezone.out: $(addprefix $(testdata)/, \ + America/Sao_Paulo Asia/Tokyo \ + Europe/London) + $(objpfx)tst-tzset.out: $(addprefix $(testdata)/XT, 1 2 3 4) ++$(objpfx)tst-bz28707.out: $(testdata)/XT5 + + test-tz-ENV = TZDIR=$(testdata) + tst-timezone-ENV = TZDIR=$(testdata) + tst-tzset-ENV = TZDIR=$(testdata) ++tst-bz28707-ENV = TZDIR=$(testdata) + + # Note this must come second in the deps list for $(built-program-cmd) to work. + zic-deps = $(objpfx)zic $(leapseconds) yearistype +@@ -122,6 +124,10 @@ $(testdata)/XT%: testdata/XT% + $(make-target-directory) + cp $< $@ + ++$(testdata)/XT%: testdata/gen-XT%.sh ++ $(SHELL) $< > $@.tmp ++ mv $@.tmp $@ ++ + $(objpfx)tzselect: tzselect.ksh $(common-objpfx)config.make + sed -e 's|TZDIR=[^}]*|TZDIR=$(zonedir)|' \ + -e '/TZVERSION=/s|see_Makefile|"$(version)"|' \ +diff --git a/timezone/testdata/gen-XT5.sh b/timezone/testdata/gen-XT5.sh +new file mode 100755 +index 0000000..3cea056 +--- /dev/null ++++ b/timezone/testdata/gen-XT5.sh +@@ -0,0 +1,16 @@ ++#! /bin/sh ++ ++# This test-case is the tzfile for America/Asuncion ++# generated by tzlib-2021e as follows, using the tzlib-2021e ++# zic: "zic -d DEST -r @1546300800 -L /dev/null -b slim ++# SOURCE/southamerica". Note that in its type 2 header, it ++# has two entries in its "time-types" array (types), but ++# only one entry in its "transition types" array ++# (type_idxs). ++ ++printf \ ++'TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0'\ ++'\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\0\0\0\0TZif2\0\0\0\0\0\0\0\0'\ ++'\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\2\0\0\0\b\0'\ ++'\0\0\0\*\255\200\1\0\0\0\0\0\0\377\377\325\320\1\4-00\0-03\0\n'\ ++'<-04>4<-03>,M10.1.0/0,M3.4.0/0\n' +diff --git a/timezone/tst-bz28707.c b/timezone/tst-bz28707.c +new file mode 100644 +index 0000000..0a9df1e +--- /dev/null ++++ b/timezone/tst-bz28707.c +@@ -0,0 +1,46 @@ ++/* 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++/* Test that we can use a truncated timezone-file, where the time-type ++ at index 0 is not indexed by the transition-types array (and the ++ transition-types array does not contain at least both one DST and one ++ normal time members). */ ++ ++static int ++do_test (void) ++{ ++ if (setenv ("TZ", "XT5", 1)) ++ { ++ puts ("setenv failed."); ++ return 1; ++ } ++ ++ tzset (); ++ ++ return ++ /* Sanity-check that we got the right timezone-name for DST. For ++ normal time, we're likely to get "-00" (the "unspecified" marker), ++ even though the POSIX timezone string says "-04". Let's not test ++ that. */ ++ !(strcmp (tzname[1], "-03") == 0); ++} ++#include +-- +1.8.3.1 + diff --git a/tst-realpath-toolong-Fix-hurd-build.patch b/tst-realpath-toolong-Fix-hurd-build.patch new file mode 100644 index 0000000000000000000000000000000000000000..644578293fe7f2da38be2b9b0cc50b066ccf6e81 --- /dev/null +++ b/tst-realpath-toolong-Fix-hurd-build.patch @@ -0,0 +1,31 @@ +From 8c8a71c85f2ed5cc90d08d82ce645513fc907cb6 Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +Date: Mon, 24 Jan 2022 10:57:09 +0530 +Subject: [PATCH] tst-realpath-toolong: Fix hurd build + +Define PATH_MAX to a constant if it isn't already defined, like in hurd. + +Signed-off-by: Siddhesh Poyarekar +(cherry picked from commit 976db046bc3a3738f69255ae00b0a09b8e77fd9c) +--- + stdlib/tst-realpath-toolong.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/stdlib/tst-realpath-toolong.c b/stdlib/tst-realpath-toolong.c +index 8bed772..4388890 100644 +--- a/stdlib/tst-realpath-toolong.c ++++ b/stdlib/tst-realpath-toolong.c +@@ -29,6 +29,10 @@ + + #define BASENAME "tst-realpath-toolong." + ++#ifndef PATH_MAX ++# define PATH_MAX 1024 ++#endif ++ + int + do_test (void) + { +-- +1.8.3.1 + diff --git a/tst-socket-timestamp-compat.c-Check-__TIMESIZE-BZ-28.patch b/tst-socket-timestamp-compat.c-Check-__TIMESIZE-BZ-28.patch new file mode 100644 index 0000000000000000000000000000000000000000..eeab0ad64cf83caa267287da4c205629870258c0 --- /dev/null +++ b/tst-socket-timestamp-compat.c-Check-__TIMESIZE-BZ-28.patch @@ -0,0 +1,29 @@ +From 008003dc6e83439c5e04a744b7fd8197df19096e Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Sat, 29 Jan 2022 05:22:31 -0800 +Subject: [PATCH] tst-socket-timestamp-compat.c: Check __TIMESIZE [BZ #28837] + +time_t size is defined by __TIMESIZE, not __WORDSIZE. Check __TIMESIZE, +instead of __WORDSIZE, for time_t size. This fixes BZ #28837. + +(cherry pick from commit 77a602ebb0769e7ccc5f9f8e06f7fffe66f69dfc) +--- + sysdeps/unix/sysv/linux/tst-socket-timestamp-compat.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sysdeps/unix/sysv/linux/tst-socket-timestamp-compat.c b/sysdeps/unix/sysv/linux/tst-socket-timestamp-compat.c +index de261dae5a..0ff1a214e6 100644 +--- a/sysdeps/unix/sysv/linux/tst-socket-timestamp-compat.c ++++ b/sysdeps/unix/sysv/linux/tst-socket-timestamp-compat.c +@@ -237,7 +237,7 @@ do_test (void) + { + /* This test only make sense for ABIs that support 32 bit time_t socket + timestampss. */ +- if (sizeof (time_t) > 4 && __WORDSIZE == 64) ++ if (sizeof (time_t) > 4 && __TIMESIZE == 64) + return 0; + + srv = xsocket (AF_INET, SOCK_DGRAM, 0); +-- +2.27.0 + diff --git a/turn-REP_STOSB_THRESHOLD-from-2k-to-1M.patch b/turn-REP_STOSB_THRESHOLD-from-2k-to-1M.patch deleted file mode 100644 index 17bebd359694c399376c47de17087372661c9aad..0000000000000000000000000000000000000000 --- a/turn-REP_STOSB_THRESHOLD-from-2k-to-1M.patch +++ /dev/null @@ -1,45 +0,0 @@ -From dc8c5d3ba8ec3c2de8ca0898d682d89492d275b3 Mon Sep 17 00:00:00 2001 -From: Shuo Wang -Date: Tue, 2 Mar 2021 10:41:09 +0800 -Subject: [PATCH] turn REP_STOSB_THRESHOLD from 2k to 1M - -REP_STOSB_THRESHOLD is designed to choose vec mov or stosb. -The default threshold (2k) will lead to performance degradation if the -memcpy size is between 2k and 1M. ---- - sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S | 12 +++++++++++- - 1 file changed, 11 insertions(+), 1 deletion(-) - -diff --git a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S -index faa40856..76f84748 100644 ---- a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S -+++ b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S -@@ -58,6 +58,16 @@ - # endif - #endif - -+/* Threshold to use Enhanced REP STOSB. Since there is overhead to set -+ up REP STOSB operation, REP STOSB isn't faster on short data. The -+ memset micro benchmark in glibc shows that 2KB is the approximate -+ value above which REP STOSB becomes faster on processors with -+ Enhanced REP STOSB. Since the stored value is fixed, larger register -+ size has minimal impact on threshold. */ -+#ifndef REP_STOSB_THRESHOLD -+# define REP_STOSB_THRESHOLD 1048576 -+#endif -+ - #ifndef SECTION - # error SECTION is not defined! - #endif -@@ -171,7 +181,7 @@ ENTRY (MEMSET_SYMBOL (__memset, unaligned_erms)) - ret - - L(stosb_more_2x_vec): -- cmp __x86_rep_stosb_threshold(%rip), %RDX_LP -+ cmp $REP_STOSB_THRESHOLD, %RDX_LP - ja L(stosb) - #endif - L(more_2x_vec): --- -2.23.0 - diff --git a/turn-default-value-of-x86_rep_stosb_threshold_form_2K_to_1M.patch b/turn-default-value-of-x86_rep_stosb_threshold_form_2K_to_1M.patch new file mode 100644 index 0000000000000000000000000000000000000000..e9e053dece4618d2ba6bb47d561215c674a4759a --- /dev/null +++ b/turn-default-value-of-x86_rep_stosb_threshold_form_2K_to_1M.patch @@ -0,0 +1,29 @@ +From 4dee2794b8c78ccd540e3f72bc07585828e0143b Mon Sep 17 00:00:00 2001 +From: Yang Yanchao +Date: Thu, 2 Dec 2021 19:56:20 +0800 +Subject: [PATCH] turn the default value of x86_rep_stosb_threshold from 2k to 1M + +x86_rep_stosb_threshold is designed to choose vec mov or stosb. +For the libMicro, after set this x86_rep_stosb_threshold to 1 MB. +The performance of memset_256_u, memset_4k_uc, and memset_1m is improved. +The performance deteriorates in the memset_4k and memset_10k scenarios. +--- + sysdeps/x86/dl-tunables.list | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sysdeps/x86/dl-tunables.list b/sysdeps/x86/dl-tunables.list +index dd6e1d65..a4c3af69 100644 +--- a/sysdeps/x86/dl-tunables.list ++++ b/sysdeps/x86/dl-tunables.list +@@ -54,7 +54,7 @@ glibc { + # stored value is fixed, larger register size has minimal impact + # on threshold. + minval: 1 +- default: 2048 ++ default: 1048576 + } + x86_data_cache_size { + type: SIZE_T +-- +2.30.0 + diff --git a/use-region-to-instead-of-country-for-extract-timezon.patch b/use-region-to-instead-of-country-for-extract-timezon.patch new file mode 100644 index 0000000000000000000000000000000000000000..7e8eb07ef99327c3e0f688e099d67710600985ec --- /dev/null +++ b/use-region-to-instead-of-country-for-extract-timezon.patch @@ -0,0 +1,152 @@ +From 1c20cf491471a4a70f103a9d052fcca993eaa341 Mon Sep 17 00:00:00 2001 +From: Qingqing Li +Date: Tue, 22 Feb 2022 15:00:55 +0800 +Subject: [PATCH] use region to instead of country for extract timezone + selection. +Co-authored-by: liusirui +--- + timezone/tzselect.ksh | 97 +++++++++---------------------------------- + 1 file changed, 20 insertions(+), 77 deletions(-) + +diff --git a/timezone/tzselect.ksh b/timezone/tzselect.ksh +index 18fce27e..414bfa2a 100755 +--- a/timezone/tzselect.ksh ++++ b/timezone/tzselect.ksh +@@ -51,7 +51,7 @@ say() { + + coord= + location_limit=10 +-zonetabtype=zone1970 ++zonetabtype=zone + + usage="Usage: tzselect [--version] [--help] [-c COORD] [-n LIMIT] + Select a timezone interactively. +@@ -398,94 +398,38 @@ while + '` + ;; + *) +- # Get list of names of countries in the continent or ocean. +- countries=`$AWK \ ++ # Get list of regions in the continent or ocean. ++ timezones=`$AWK \ + -v continent="$continent" \ + -v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \ + ' + BEGIN { FS = "\t" } + /^#/ { next } + $3 ~ ("^" continent "/") { +- ncc = split($1, cc, /,/) ++ ncc = split($3, cc, /,/) + for (i = 1; i <= ncc; i++) + if (!cc_seen[cc[i]]++) cc_list[++ccs] = cc[i] + } + END { +- while (getline &2 'Please select a country' \ +- 'whose clocks agree with yours.' +- doselect $countries +- country=$select_result;; +- *) +- country=$countries +- esac +- +- +- # Get list of timezones in the country. +- regions=`$AWK \ +- -v country="$country" \ +- -v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \ +- ' +- BEGIN { +- FS = "\t" +- cc = country +- while (getline &2 'Please select one of the following timezones.' +- doselect $regions +- region=$select_result;; +- *) +- region=$regions +- esac ++ regions=[] ++ index=0 ++ for item in $timezones; do ++ regions[$index]=`echo $item | awk -F '/' '{print $2}'` ++ index=$(($index+1)) ++ done ++ echo >&2 'Please select a timezone' \ ++ 'whose clocks agree with yours.' ++ doselect ${regions[@]} ++ region=$select_result + + # Determine TZ from country and region. +- TZ=`$AWK \ +- -v country="$country" \ +- -v region="$region" \ +- -v TZ_COUNTRY_TABLE="$TZ_COUNTRY_TABLE" \ +- ' +- BEGIN { +- FS = "\t" +- cc = country +- while (getline &2 "" + echo >&2 "The following information has been given:" + echo >&2 "" +- case $country%$region%$coord in +- ?*%?*%) say >&2 " $country$newline $region";; +- ?*%%) say >&2 " $country";; +- %?*%?*) say >&2 " coord $coord$newline $region";; +- %%?*) say >&2 " coord $coord";; ++ case $region%$coord in ++ ?*%) say >&2 " $region";; ++ ?*%?*) say >&2 " coord $coord$newline $region";; ++ %?*) say >&2 " coord $coord";; + *) say >&2 " TZ='$TZ'" + esac + say >&2 "" +-- +2.27.0 + diff --git a/x86-64-Optimize-load-of-all-bits-set-into-ZMM-regist.patch b/x86-64-Optimize-load-of-all-bits-set-into-ZMM-regist.patch new file mode 100644 index 0000000000000000000000000000000000000000..924e63c8f380a7f4b395c0b516c96193fce71e2a --- /dev/null +++ b/x86-64-Optimize-load-of-all-bits-set-into-ZMM-regist.patch @@ -0,0 +1,267 @@ +From 78c9ec9000f873abe7a15a91b87080a2e4308260 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Fri, 20 Aug 2021 06:42:24 -0700 +Subject: [PATCH] x86-64: Optimize load of all bits set into ZMM register [BZ + #28252] + +Optimize loads of all bits set into ZMM register in AVX512 SVML codes +by replacing + + vpbroadcastq .L_2il0floatpacket.16(%rip), %zmmX + +and + + vmovups .L_2il0floatpacket.13(%rip), %zmmX + +with + vpternlogd $0xff, %zmmX, %zmmX, %zmmX + +This fixes BZ #28252. +--- + sysdeps/x86_64/fpu/multiarch/svml_d_cos8_core_avx512.S | 7 +------ + sysdeps/x86_64/fpu/multiarch/svml_d_log8_core_avx512.S | 7 +------ + sysdeps/x86_64/fpu/multiarch/svml_d_sin8_core_avx512.S | 7 +------ + sysdeps/x86_64/fpu/multiarch/svml_d_sincos8_core_avx512.S | 7 +------ + sysdeps/x86_64/fpu/multiarch/svml_s_cosf16_core_avx512.S | 7 +------ + sysdeps/x86_64/fpu/multiarch/svml_s_expf16_core_avx512.S | 7 +------ + sysdeps/x86_64/fpu/multiarch/svml_s_logf16_core_avx512.S | 7 +------ + sysdeps/x86_64/fpu/multiarch/svml_s_powf16_core_avx512.S | 12 ++---------- + sysdeps/x86_64/fpu/multiarch/svml_s_sincosf16_core_avx512.S | 7 +------ + sysdeps/x86_64/fpu/multiarch/svml_s_sinf16_core_avx512.S | 7 +------ + 10 files changed, 11 insertions(+), 64 deletions(-) + +diff --git a/sysdeps/x86_64/fpu/multiarch/svml_d_cos8_core_avx512.S b/sysdeps/x86_64/fpu/multiarch/svml_d_cos8_core_avx512.S +index e68fcdb..58e588a 100644 +--- a/sysdeps/x86_64/fpu/multiarch/svml_d_cos8_core_avx512.S ++++ b/sysdeps/x86_64/fpu/multiarch/svml_d_cos8_core_avx512.S +@@ -265,7 +265,7 @@ WRAPPER_IMPL_AVX512 _ZGVdN4v_cos + vmovaps %zmm0, %zmm8 + + /* Check for large arguments path */ +- vpbroadcastq .L_2il0floatpacket.16(%rip), %zmm2 ++ vpternlogd $0xff, %zmm2, %zmm2, %zmm2 + + /* + ARGUMENT RANGE REDUCTION: +@@ -456,8 +456,3 @@ WRAPPER_IMPL_AVX512 _ZGVdN4v_cos + jmp .LBL_2_7 + #endif + END (_ZGVeN8v_cos_skx) +- +- .section .rodata, "a" +-.L_2il0floatpacket.16: +- .long 0xffffffff,0xffffffff +- .type .L_2il0floatpacket.16,@object +diff --git a/sysdeps/x86_64/fpu/multiarch/svml_d_log8_core_avx512.S b/sysdeps/x86_64/fpu/multiarch/svml_d_log8_core_avx512.S +index dfa2aca..f5f117d 100644 +--- a/sysdeps/x86_64/fpu/multiarch/svml_d_log8_core_avx512.S ++++ b/sysdeps/x86_64/fpu/multiarch/svml_d_log8_core_avx512.S +@@ -274,7 +274,7 @@ WRAPPER_IMPL_AVX512 _ZGVdN4v_log + + /* preserve mantissa, set input exponent to 2^(-10) */ + vpternlogq $248, _ExpMask(%rax), %zmm3, %zmm2 +- vpbroadcastq .L_2il0floatpacket.12(%rip), %zmm1 ++ vpternlogd $0xff, %zmm1, %zmm1, %zmm1 + vpsrlq $32, %zmm4, %zmm6 + + /* reciprocal approximation good to at least 11 bits */ +@@ -461,8 +461,3 @@ WRAPPER_IMPL_AVX512 _ZGVdN4v_log + jmp .LBL_2_7 + #endif + END (_ZGVeN8v_log_skx) +- +- .section .rodata, "a" +-.L_2il0floatpacket.12: +- .long 0xffffffff,0xffffffff +- .type .L_2il0floatpacket.12,@object +diff --git a/sysdeps/x86_64/fpu/multiarch/svml_d_sin8_core_avx512.S b/sysdeps/x86_64/fpu/multiarch/svml_d_sin8_core_avx512.S +index be8ab7c..48d251d 100644 +--- a/sysdeps/x86_64/fpu/multiarch/svml_d_sin8_core_avx512.S ++++ b/sysdeps/x86_64/fpu/multiarch/svml_d_sin8_core_avx512.S +@@ -261,7 +261,7 @@ WRAPPER_IMPL_AVX512 _ZGVdN4v_sin + andq $-64, %rsp + subq $1280, %rsp + movq __svml_d_trig_data@GOTPCREL(%rip), %rax +- vpbroadcastq .L_2il0floatpacket.14(%rip), %zmm14 ++ vpternlogd $0xff, %zmm1, %zmm1, %zmm14 + vmovups __dAbsMask(%rax), %zmm7 + vmovups __dInvPI(%rax), %zmm2 + vmovups __dRShifter(%rax), %zmm1 +@@ -458,8 +458,3 @@ WRAPPER_IMPL_AVX512 _ZGVdN4v_sin + jmp .LBL_2_7 + #endif + END (_ZGVeN8v_sin_skx) +- +- .section .rodata, "a" +-.L_2il0floatpacket.14: +- .long 0xffffffff,0xffffffff +- .type .L_2il0floatpacket.14,@object +diff --git a/sysdeps/x86_64/fpu/multiarch/svml_d_sincos8_core_avx512.S b/sysdeps/x86_64/fpu/multiarch/svml_d_sincos8_core_avx512.S +index 6118870..a4944a4 100644 +--- a/sysdeps/x86_64/fpu/multiarch/svml_d_sincos8_core_avx512.S ++++ b/sysdeps/x86_64/fpu/multiarch/svml_d_sincos8_core_avx512.S +@@ -430,7 +430,7 @@ WRAPPER_IMPL_AVX512_fFF _ZGVdN4vl8l8_sincos + + /* SinPoly = SinR*SinPoly */ + vfmadd213pd %zmm5, %zmm5, %zmm4 +- vpbroadcastq .L_2il0floatpacket.15(%rip), %zmm3 ++ vpternlogd $0xff, %zmm3, %zmm3, %zmm3 + + /* Update Cos result's sign */ + vxorpd %zmm2, %zmm1, %zmm1 +@@ -741,8 +741,3 @@ END (_ZGVeN8vvv_sincos_knl) + ENTRY (_ZGVeN8vvv_sincos_skx) + WRAPPER_AVX512_vvv_vl8l8 _ZGVeN8vl8l8_sincos_skx + END (_ZGVeN8vvv_sincos_skx) +- +- .section .rodata, "a" +-.L_2il0floatpacket.15: +- .long 0xffffffff,0xffffffff +- .type .L_2il0floatpacket.15,@object +diff --git a/sysdeps/x86_64/fpu/multiarch/svml_s_cosf16_core_avx512.S b/sysdeps/x86_64/fpu/multiarch/svml_s_cosf16_core_avx512.S +index f671d60..fe8474f 100644 +--- a/sysdeps/x86_64/fpu/multiarch/svml_s_cosf16_core_avx512.S ++++ b/sysdeps/x86_64/fpu/multiarch/svml_s_cosf16_core_avx512.S +@@ -278,7 +278,7 @@ WRAPPER_IMPL_AVX512 _ZGVdN8v_cosf + X = X - Y*PI1 - Y*PI2 - Y*PI3 + */ + vmovaps %zmm0, %zmm6 +- vmovups .L_2il0floatpacket.13(%rip), %zmm12 ++ vpternlogd $0xff, %zmm12, %zmm12, %zmm12 + vmovups __sRShifter(%rax), %zmm3 + vmovups __sPI1_FMA(%rax), %zmm5 + vmovups __sA9_FMA(%rax), %zmm9 +@@ -453,8 +453,3 @@ WRAPPER_IMPL_AVX512 _ZGVdN8v_cosf + jmp .LBL_2_7 + #endif + END (_ZGVeN16v_cosf_skx) +- +- .section .rodata, "a" +-.L_2il0floatpacket.13: +- .long 0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff +- .type .L_2il0floatpacket.13,@object +diff --git a/sysdeps/x86_64/fpu/multiarch/svml_s_expf16_core_avx512.S b/sysdeps/x86_64/fpu/multiarch/svml_s_expf16_core_avx512.S +index 637bfe3..229b782 100644 +--- a/sysdeps/x86_64/fpu/multiarch/svml_s_expf16_core_avx512.S ++++ b/sysdeps/x86_64/fpu/multiarch/svml_s_expf16_core_avx512.S +@@ -264,7 +264,7 @@ WRAPPER_IMPL_AVX512 _ZGVdN8v_expf + vmovaps %zmm0, %zmm7 + + /* compare against threshold */ +- vmovups .L_2il0floatpacket.13(%rip), %zmm3 ++ vpternlogd $0xff, %zmm3, %zmm3, %zmm3 + vmovups __sInvLn2(%rax), %zmm4 + vmovups __sShifter(%rax), %zmm1 + vmovups __sLn2hi(%rax), %zmm6 +@@ -440,8 +440,3 @@ WRAPPER_IMPL_AVX512 _ZGVdN8v_expf + + #endif + END (_ZGVeN16v_expf_skx) +- +- .section .rodata, "a" +-.L_2il0floatpacket.13: +- .long 0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff +- .type .L_2il0floatpacket.13,@object +diff --git a/sysdeps/x86_64/fpu/multiarch/svml_s_logf16_core_avx512.S b/sysdeps/x86_64/fpu/multiarch/svml_s_logf16_core_avx512.S +index 9d790fb..fa2aae9 100644 +--- a/sysdeps/x86_64/fpu/multiarch/svml_s_logf16_core_avx512.S ++++ b/sysdeps/x86_64/fpu/multiarch/svml_s_logf16_core_avx512.S +@@ -235,7 +235,7 @@ WRAPPER_IMPL_AVX512 _ZGVdN8v_logf + andq $-64, %rsp + subq $1280, %rsp + movq __svml_slog_data@GOTPCREL(%rip), %rax +- vmovups .L_2il0floatpacket.7(%rip), %zmm6 ++ vpternlogd $0xff, %zmm6, %zmm6, %zmm6 + vmovups _iBrkValue(%rax), %zmm4 + vmovups _sPoly_7(%rax), %zmm8 + +@@ -409,8 +409,3 @@ WRAPPER_IMPL_AVX512 _ZGVdN8v_logf + + #endif + END (_ZGVeN16v_logf_skx) +- +- .section .rodata, "a" +-.L_2il0floatpacket.7: +- .long 0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff +- .type .L_2il0floatpacket.7,@object +diff --git a/sysdeps/x86_64/fpu/multiarch/svml_s_powf16_core_avx512.S b/sysdeps/x86_64/fpu/multiarch/svml_s_powf16_core_avx512.S +index c5c43c4..6aea2a4 100644 +--- a/sysdeps/x86_64/fpu/multiarch/svml_s_powf16_core_avx512.S ++++ b/sysdeps/x86_64/fpu/multiarch/svml_s_powf16_core_avx512.S +@@ -385,7 +385,7 @@ WRAPPER_IMPL_AVX512_ff _ZGVdN8vv_powf + vpsrlq $32, %zmm3, %zmm2 + vpmovqd %zmm2, %ymm11 + vcvtps2pd %ymm14, %zmm13 +- vmovups .L_2il0floatpacket.23(%rip), %zmm14 ++ vpternlogd $0xff, %zmm14, %zmm14, %zmm14 + vmovaps %zmm14, %zmm26 + vpandd _ABSMASK(%rax), %zmm1, %zmm8 + vpcmpd $1, _INF(%rax), %zmm8, %k2 +@@ -427,7 +427,7 @@ WRAPPER_IMPL_AVX512_ff _ZGVdN8vv_powf + vpmovqd %zmm11, %ymm5 + vpxord %zmm10, %zmm10, %zmm10 + vgatherdpd _Log2Rcp_lookup(%rax,%ymm4), %zmm10{%k3} +- vpbroadcastq .L_2il0floatpacket.24(%rip), %zmm4 ++ vpternlogd $0xff, %zmm4, %zmm4, %zmm4 + vpxord %zmm11, %zmm11, %zmm11 + vcvtdq2pd %ymm7, %zmm7 + vgatherdpd _Log2Rcp_lookup(%rax,%ymm5), %zmm11{%k1} +@@ -643,11 +643,3 @@ WRAPPER_IMPL_AVX512_ff _ZGVdN8vv_powf + jmp .LBL_2_7 + #endif + END (_ZGVeN16vv_powf_skx) +- +- .section .rodata, "a" +-.L_2il0floatpacket.23: +- .long 0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff +- .type .L_2il0floatpacket.23,@object +-.L_2il0floatpacket.24: +- .long 0xffffffff,0xffffffff +- .type .L_2il0floatpacket.24,@object +diff --git a/sysdeps/x86_64/fpu/multiarch/svml_s_sincosf16_core_avx512.S b/sysdeps/x86_64/fpu/multiarch/svml_s_sincosf16_core_avx512.S +index 9cf359c..a446c50 100644 +--- a/sysdeps/x86_64/fpu/multiarch/svml_s_sincosf16_core_avx512.S ++++ b/sysdeps/x86_64/fpu/multiarch/svml_s_sincosf16_core_avx512.S +@@ -317,7 +317,7 @@ WRAPPER_IMPL_AVX512_fFF _ZGVdN8vvv_sincosf + + /* Result sign calculations */ + vpternlogd $150, %zmm0, %zmm14, %zmm1 +- vmovups .L_2il0floatpacket.13(%rip), %zmm14 ++ vpternlogd $0xff, %zmm14, %zmm14, %zmm14 + + /* Add correction term 0.5 for cos() part */ + vaddps %zmm8, %zmm5, %zmm15 +@@ -748,8 +748,3 @@ END (_ZGVeN16vvv_sincosf_knl) + ENTRY (_ZGVeN16vvv_sincosf_skx) + WRAPPER_AVX512_vvv_vl4l4 _ZGVeN16vl4l4_sincosf_skx + END (_ZGVeN16vvv_sincosf_skx) +- +- .section .rodata, "a" +-.L_2il0floatpacket.13: +- .long 0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff +- .type .L_2il0floatpacket.13,@object +diff --git a/sysdeps/x86_64/fpu/multiarch/svml_s_sinf16_core_avx512.S b/sysdeps/x86_64/fpu/multiarch/svml_s_sinf16_core_avx512.S +index bd05109..c1b352d 100644 +--- a/sysdeps/x86_64/fpu/multiarch/svml_s_sinf16_core_avx512.S ++++ b/sysdeps/x86_64/fpu/multiarch/svml_s_sinf16_core_avx512.S +@@ -280,7 +280,7 @@ WRAPPER_IMPL_AVX512 _ZGVdN8v_sinf + movq __svml_s_trig_data@GOTPCREL(%rip), %rax + + /* Check for large and special values */ +- vmovups .L_2il0floatpacket.11(%rip), %zmm14 ++ vpternlogd $0xff, %zmm14, %zmm14, %zmm14 + vmovups __sAbsMask(%rax), %zmm5 + vmovups __sInvPI(%rax), %zmm1 + vmovups __sRShifter(%rax), %zmm2 +@@ -472,8 +472,3 @@ WRAPPER_IMPL_AVX512 _ZGVdN8v_sinf + jmp .LBL_2_7 + #endif + END (_ZGVeN16v_sinf_skx) +- +- .section .rodata, "a" +-.L_2il0floatpacket.11: +- .long 0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff +- .type .L_2il0floatpacket.11,@object +-- +1.8.3.1 + diff --git a/x86-64-Use-testl-to-check-__x86_string_control.patch b/x86-64-Use-testl-to-check-__x86_string_control.patch new file mode 100644 index 0000000000000000000000000000000000000000..363930e209a2b3400809eefbe647cf306b263126 --- /dev/null +++ b/x86-64-Use-testl-to-check-__x86_string_control.patch @@ -0,0 +1,38 @@ +From 3c8b9879cab6d41787bc5b14c1748f62fd6d0e5f Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Sat, 28 Aug 2021 06:10:38 -0700 +Subject: [PATCH] x86-64: Use testl to check __x86_string_control + +Use testl, instead of andl, to check __x86_string_control to avoid +updating __x86_string_control. + +Reviewed-by: Carlos O'Donell +--- + sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +index 9f02624..abde843 100644 +--- a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +@@ -325,7 +325,7 @@ L(movsb): + /* Avoid slow backward REP MOVSB. */ + jb L(more_8x_vec_backward) + # if AVOID_SHORT_DISTANCE_REP_MOVSB +- andl $X86_STRING_CONTROL_AVOID_SHORT_DISTANCE_REP_MOVSB, __x86_string_control(%rip) ++ testl $X86_STRING_CONTROL_AVOID_SHORT_DISTANCE_REP_MOVSB, __x86_string_control(%rip) + jz 3f + movq %rdi, %rcx + subq %rsi, %rcx +@@ -333,7 +333,7 @@ L(movsb): + # endif + 1: + # if AVOID_SHORT_DISTANCE_REP_MOVSB +- andl $X86_STRING_CONTROL_AVOID_SHORT_DISTANCE_REP_MOVSB, __x86_string_control(%rip) ++ testl $X86_STRING_CONTROL_AVOID_SHORT_DISTANCE_REP_MOVSB, __x86_string_control(%rip) + jz 3f + movq %rsi, %rcx + subq %rdi, %rcx +-- +1.8.3.1 + diff --git a/x86-Black-list-more-Intel-CPUs-for-TSX-BZ-27398.patch b/x86-Black-list-more-Intel-CPUs-for-TSX-BZ-27398.patch new file mode 100644 index 0000000000000000000000000000000000000000..67704e018864da4256c0d6aeec9e9ab0c1217bde --- /dev/null +++ b/x86-Black-list-more-Intel-CPUs-for-TSX-BZ-27398.patch @@ -0,0 +1,67 @@ +From b952c25dc7adf0684c53ad72d1d667da0348c929 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Fri, 14 Jan 2022 14:48:01 -0800 +Subject: [PATCH] x86: Black list more Intel CPUs for TSX [BZ #27398] + +Disable TSX and enable RTM_ALWAYS_ABORT for Intel CPUs listed in: + +https://www.intel.com/content/www/us/en/support/articles/000059422/processors.html + +This fixes BZ #27398. + +Reviewed-by: Noah Goldstein +(cherry picked from commit 1e000d3d33211d5a954300e2a69b90f93f18a1a1) +--- + sysdeps/x86/cpu-features.c | 34 +++++++++++++++++++++++++++++++--- + 1 file changed, 31 insertions(+), 3 deletions(-) + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 645bba6314..de4e3c3b72 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -507,11 +507,39 @@ init_cpu_features (struct cpu_features *cpu_features) + break; + } + +- /* Disable TSX on some Haswell processors to avoid TSX on kernels that +- weren't updated with the latest microcode package (which disables +- broken feature by default). */ ++ /* Disable TSX on some processors to avoid TSX on kernels that ++ weren't updated with the latest microcode package (which ++ disables broken feature by default). */ + switch (model) + { ++ case 0x55: ++ if (stepping <= 5) ++ goto disable_tsx; ++ break; ++ case 0x8e: ++ /* NB: Although the errata documents that for model == 0x8e, ++ only 0xb stepping or lower are impacted, the intention of ++ the errata was to disable TSX on all client processors on ++ all steppings. Include 0xc stepping which is an Intel ++ Core i7-8665U, a client mobile processor. */ ++ case 0x9e: ++ if (stepping > 0xc) ++ break; ++ /* Fall through. */ ++ case 0x4e: ++ case 0x5e: ++ { ++ /* Disable Intel TSX and enable RTM_ALWAYS_ABORT for ++ processors listed in: ++ ++https://www.intel.com/content/www/us/en/support/articles/000059422/processors.html ++ */ ++disable_tsx: ++ CPU_FEATURE_UNSET (cpu_features, HLE); ++ CPU_FEATURE_UNSET (cpu_features, RTM); ++ CPU_FEATURE_SET (cpu_features, RTM_ALWAYS_ABORT); ++ } ++ break; + case 0x3f: + /* Xeon E7 v3 with stepping >= 4 has working TSX. */ + if (stepping >= 4) +-- +2.27.0 + diff --git a/x86-Fallback-str-wcs-cmp-RTM-in-the-ncmp-overflow-ca.patch b/x86-Fallback-str-wcs-cmp-RTM-in-the-ncmp-overflow-ca.patch new file mode 100644 index 0000000000000000000000000000000000000000..6bfbc68748ed7260b7b63289e064d97064463371 --- /dev/null +++ b/x86-Fallback-str-wcs-cmp-RTM-in-the-ncmp-overflow-ca.patch @@ -0,0 +1,132 @@ +From 38e0d2479413ccdbc02b4c9e9e246eca31e956c9 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Tue, 15 Feb 2022 08:18:15 -0600 +Subject: [PATCH] x86: Fallback {str|wcs}cmp RTM in the ncmp overflow case [BZ + #28896] + +In the overflow fallback strncmp-avx2-rtm and wcsncmp-avx2-rtm would +call strcmp-avx2 and wcscmp-avx2 respectively. This would have +not checks around vzeroupper and would trigger spurious +aborts. This commit fixes that. + +test-strcmp, test-strncmp, test-wcscmp, and test-wcsncmp all pass on +AVX2 machines with and without RTM. + +Co-authored-by: H.J. Lu + +(cherry picked from commit c6272098323153db373f2986c67786ea8c85f1cf) +--- + sysdeps/x86/Makefile | 2 +- + sysdeps/x86/tst-strncmp-rtm.c | 17 ++++++++++++++++- + sysdeps/x86_64/multiarch/strcmp-avx2.S | 2 +- + sysdeps/x86_64/multiarch/strncmp-avx2-rtm.S | 1 + + sysdeps/x86_64/multiarch/strncmp-avx2.S | 1 + + sysdeps/x86_64/multiarch/wcsncmp-avx2-rtm.S | 2 +- + sysdeps/x86_64/multiarch/wcsncmp-avx2.S | 2 +- + 7 files changed, 22 insertions(+), 5 deletions(-) + +diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile +index 5ee06f9473..6c3e08a3d7 100644 +--- a/sysdeps/x86/Makefile ++++ b/sysdeps/x86/Makefile +@@ -104,7 +104,7 @@ CFLAGS-tst-memset-rtm.c += -mrtm + CFLAGS-tst-strchr-rtm.c += -mrtm + CFLAGS-tst-strcpy-rtm.c += -mrtm + CFLAGS-tst-strlen-rtm.c += -mrtm +-CFLAGS-tst-strncmp-rtm.c += -mrtm ++CFLAGS-tst-strncmp-rtm.c += -mrtm -Wno-error + CFLAGS-tst-strrchr-rtm.c += -mrtm + endif + +diff --git a/sysdeps/x86/tst-strncmp-rtm.c b/sysdeps/x86/tst-strncmp-rtm.c +index 236ad951b5..4d0004b58a 100644 +--- a/sysdeps/x86/tst-strncmp-rtm.c ++++ b/sysdeps/x86/tst-strncmp-rtm.c +@@ -16,6 +16,7 @@ + License along with the GNU C Library; if not, see + . */ + ++#include + #include + + #define LOOP 3000 +@@ -45,8 +46,22 @@ function (void) + return 1; + } + ++__attribute__ ((noinline, noclone)) ++static int ++function_overflow (void) ++{ ++ if (strncmp (string1, string2, SIZE_MAX) == 0) ++ return 0; ++ else ++ return 1; ++} ++ + static int + do_test (void) + { +- return do_test_1 ("strncmp", LOOP, prepare, function); ++ int status = do_test_1 ("strncmp", LOOP, prepare, function); ++ if (status != EXIT_SUCCESS) ++ return status; ++ status = do_test_1 ("strncmp", LOOP, prepare, function_overflow); ++ return status; + } +diff --git a/sysdeps/x86_64/multiarch/strcmp-avx2.S b/sysdeps/x86_64/multiarch/strcmp-avx2.S +index 3dfcb1bf80..fa70c994fc 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-avx2.S ++++ b/sysdeps/x86_64/multiarch/strcmp-avx2.S +@@ -95,7 +95,7 @@ ENTRY (STRCMP) + length to bound a valid memory region. In these cases just use + 'wcscmp'. */ + shrq $56, %rcx +- jnz __wcscmp_avx2 ++ jnz OVERFLOW_STRCMP + # endif + /* Convert units: from wide to byte char. */ + shl $2, %RDX_LP +diff --git a/sysdeps/x86_64/multiarch/strncmp-avx2-rtm.S b/sysdeps/x86_64/multiarch/strncmp-avx2-rtm.S +index 37d1224bb9..68bad365ba 100644 +--- a/sysdeps/x86_64/multiarch/strncmp-avx2-rtm.S ++++ b/sysdeps/x86_64/multiarch/strncmp-avx2-rtm.S +@@ -1,3 +1,4 @@ + #define STRCMP __strncmp_avx2_rtm + #define USE_AS_STRNCMP 1 ++#define OVERFLOW_STRCMP __strcmp_avx2_rtm + #include "strcmp-avx2-rtm.S" +diff --git a/sysdeps/x86_64/multiarch/strncmp-avx2.S b/sysdeps/x86_64/multiarch/strncmp-avx2.S +index 1678bcc235..f138e9f1fd 100644 +--- a/sysdeps/x86_64/multiarch/strncmp-avx2.S ++++ b/sysdeps/x86_64/multiarch/strncmp-avx2.S +@@ -1,3 +1,4 @@ + #define STRCMP __strncmp_avx2 + #define USE_AS_STRNCMP 1 ++#define OVERFLOW_STRCMP __strcmp_avx2 + #include "strcmp-avx2.S" +diff --git a/sysdeps/x86_64/multiarch/wcsncmp-avx2-rtm.S b/sysdeps/x86_64/multiarch/wcsncmp-avx2-rtm.S +index 4e88c70cc6..f467582cbe 100644 +--- a/sysdeps/x86_64/multiarch/wcsncmp-avx2-rtm.S ++++ b/sysdeps/x86_64/multiarch/wcsncmp-avx2-rtm.S +@@ -1,5 +1,5 @@ + #define STRCMP __wcsncmp_avx2_rtm + #define USE_AS_STRNCMP 1 + #define USE_AS_WCSCMP 1 +- ++#define OVERFLOW_STRCMP __wcscmp_avx2_rtm + #include "strcmp-avx2-rtm.S" +diff --git a/sysdeps/x86_64/multiarch/wcsncmp-avx2.S b/sysdeps/x86_64/multiarch/wcsncmp-avx2.S +index 4fa1de4d3f..e9ede522b8 100644 +--- a/sysdeps/x86_64/multiarch/wcsncmp-avx2.S ++++ b/sysdeps/x86_64/multiarch/wcsncmp-avx2.S +@@ -1,5 +1,5 @@ + #define STRCMP __wcsncmp_avx2 + #define USE_AS_STRNCMP 1 + #define USE_AS_WCSCMP 1 +- ++#define OVERFLOW_STRCMP __wcscmp_avx2 + #include "strcmp-avx2.S" +-- +2.27.0 + diff --git a/x86-Fix-TEST_NAME-to-make-it-a-string-in-tst-strncmp.patch b/x86-Fix-TEST_NAME-to-make-it-a-string-in-tst-strncmp.patch new file mode 100644 index 0000000000000000000000000000000000000000..2b231d1d40aace47f11ba781375e2e8d6bcbf56a --- /dev/null +++ b/x86-Fix-TEST_NAME-to-make-it-a-string-in-tst-strncmp.patch @@ -0,0 +1,37 @@ +From 15b00d2af0e56dcc8c244a36d6872d301b0c7185 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Fri, 18 Feb 2022 17:00:25 -0600 +Subject: [PATCH] x86: Fix TEST_NAME to make it a string in tst-strncmp-rtm.c + +Previously TEST_NAME was passing a function pointer. This didn't fail +because of the -Wno-error flag (to allow for overflow sizes passed +to strncmp/wcsncmp) + +Reviewed-by: H.J. Lu +(cherry picked from commit b98d0bbf747f39770e0caba7e984ce9f8f900330) +--- + sysdeps/x86/tst-strncmp-rtm.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sysdeps/x86/tst-strncmp-rtm.c b/sysdeps/x86/tst-strncmp-rtm.c +index 4e9f094f39..aef9866cf2 100644 +--- a/sysdeps/x86/tst-strncmp-rtm.c ++++ b/sysdeps/x86/tst-strncmp-rtm.c +@@ -23,12 +23,12 @@ + # define CHAR wchar_t + # define MEMSET wmemset + # define STRNCMP wcsncmp +-# define TEST_NAME wcsncmp ++# define TEST_NAME "wcsncmp" + #else /* !WIDE */ + # define CHAR char + # define MEMSET memset + # define STRNCMP strncmp +-# define TEST_NAME strncmp ++# define TEST_NAME "strncmp" + #endif /* !WIDE */ + + +-- +2.27.0 + diff --git a/x86-Fix-__wcsncmp_avx2-in-strcmp-avx2.S-BZ-28755.patch b/x86-Fix-__wcsncmp_avx2-in-strcmp-avx2.S-BZ-28755.patch new file mode 100644 index 0000000000000000000000000000000000000000..7b8597b606c1b80532038110ab880618ae192e35 --- /dev/null +++ b/x86-Fix-__wcsncmp_avx2-in-strcmp-avx2.S-BZ-28755.patch @@ -0,0 +1,40 @@ +From ddf0992cf57a93200e0c782e2a94d0733a5a0b87 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Sun, 9 Jan 2022 16:02:21 -0600 +Subject: [PATCH] x86: Fix __wcsncmp_avx2 in strcmp-avx2.S [BZ# 28755] + +Fixes [BZ# 28755] for wcsncmp by redirecting length >= 2^56 to +__wcscmp_avx2. For x86_64 this covers the entire address range so any +length larger could not possibly be used to bound `s1` or `s2`. + +test-strcmp, test-strncmp, test-wcscmp, and test-wcsncmp all pass. + +Signed-off-by: Noah Goldstein +--- + sysdeps/x86_64/multiarch/strcmp-avx2.S | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/sysdeps/x86_64/multiarch/strcmp-avx2.S b/sysdeps/x86_64/multiarch/strcmp-avx2.S +index a45f9d2..9c73b58 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-avx2.S ++++ b/sysdeps/x86_64/multiarch/strcmp-avx2.S +@@ -87,6 +87,16 @@ ENTRY (STRCMP) + je L(char0) + jb L(zero) + # ifdef USE_AS_WCSCMP ++# ifndef __ILP32__ ++ movq %rdx, %rcx ++ /* Check if length could overflow when multiplied by ++ sizeof(wchar_t). Checking top 8 bits will cover all potential ++ overflow cases as well as redirect cases where its impossible to ++ length to bound a valid memory region. In these cases just use ++ 'wcscmp'. */ ++ shrq $56, %rcx ++ jnz __wcscmp_avx2 ++# endif + /* Convert units: from wide to byte char. */ + shl $2, %RDX_LP + # endif +-- +1.8.3.1 + diff --git a/x86-Fix-__wcsncmp_evex-in-strcmp-evex.S-BZ-28755.patch b/x86-Fix-__wcsncmp_evex-in-strcmp-evex.S-BZ-28755.patch new file mode 100644 index 0000000000000000000000000000000000000000..2b5227e43e657a1551c79389e201432de8288754 --- /dev/null +++ b/x86-Fix-__wcsncmp_evex-in-strcmp-evex.S-BZ-28755.patch @@ -0,0 +1,40 @@ +From 7e08db3359c86c94918feb33a1182cd0ff3bb10b Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Sun, 9 Jan 2022 16:02:28 -0600 +Subject: [PATCH] x86: Fix __wcsncmp_evex in strcmp-evex.S [BZ# 28755] + +Fixes [BZ# 28755] for wcsncmp by redirecting length >= 2^56 to +__wcscmp_evex. For x86_64 this covers the entire address range so any +length larger could not possibly be used to bound `s1` or `s2`. + +test-strcmp, test-strncmp, test-wcscmp, and test-wcsncmp all pass. + +Signed-off-by: Noah Goldstein +--- + sysdeps/x86_64/multiarch/strcmp-evex.S | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/sysdeps/x86_64/multiarch/strcmp-evex.S b/sysdeps/x86_64/multiarch/strcmp-evex.S +index 1d971f3..0cd939d 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-evex.S ++++ b/sysdeps/x86_64/multiarch/strcmp-evex.S +@@ -104,6 +104,16 @@ ENTRY (STRCMP) + je L(char0) + jb L(zero) + # ifdef USE_AS_WCSCMP ++# ifndef __ILP32__ ++ movq %rdx, %rcx ++ /* Check if length could overflow when multiplied by ++ sizeof(wchar_t). Checking top 8 bits will cover all potential ++ overflow cases as well as redirect cases where its impossible to ++ length to bound a valid memory region. In these cases just use ++ 'wcscmp'. */ ++ shrq $56, %rcx ++ jnz __wcscmp_evex ++# endif + /* Convert units: from wide to byte char. */ + shl $2, %RDX_LP + # endif +-- +1.8.3.1 + diff --git a/x86-Test-wcscmp-RTM-in-the-wcsncmp-overflow-case-BZ-.patch b/x86-Test-wcscmp-RTM-in-the-wcsncmp-overflow-case-BZ-.patch new file mode 100644 index 0000000000000000000000000000000000000000..6d7469ba21b33340fb00618268a7646bbed47b23 --- /dev/null +++ b/x86-Test-wcscmp-RTM-in-the-wcsncmp-overflow-case-BZ-.patch @@ -0,0 +1,147 @@ +From d093b677c36ef4b360bf30483b68b95d9f0ad1d2 Mon Sep 17 00:00:00 2001 +From: Noah Goldstein +Date: Fri, 18 Feb 2022 14:19:15 -0600 +Subject: [PATCH] x86: Test wcscmp RTM in the wcsncmp overflow case [BZ #28896] + +In the overflow fallback strncmp-avx2-rtm and wcsncmp-avx2-rtm would +call strcmp-avx2 and wcscmp-avx2 respectively. This would have +not checks around vzeroupper and would trigger spurious +aborts. This commit fixes that. + +test-strcmp, test-strncmp, test-wcscmp, and test-wcsncmp all pass on +AVX2 machines with and without RTM. +Reviewed-by: H.J. Lu + +(cherry picked from commit 7835d611af0854e69a0c71e3806f8fe379282d6f) +--- + sysdeps/x86/Makefile | 5 ++++- + sysdeps/x86/tst-strncmp-rtm.c | 32 +++++++++++++++++++++++--------- + sysdeps/x86/tst-wcsncmp-rtm.c | 21 +++++++++++++++++++++ + 3 files changed, 48 insertions(+), 10 deletions(-) + create mode 100644 sysdeps/x86/tst-wcsncmp-rtm.c + +diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile +index 6c3e08a3d7..d7fe68609f 100644 +--- a/sysdeps/x86/Makefile ++++ b/sysdeps/x86/Makefile +@@ -94,7 +94,9 @@ tests += \ + tst-strcpy-rtm \ + tst-strlen-rtm \ + tst-strncmp-rtm \ +- tst-strrchr-rtm ++ tst-strrchr-rtm \ ++ tst-wcsncmp-rtm \ ++# tests + + CFLAGS-tst-memchr-rtm.c += -mrtm + CFLAGS-tst-memcmp-rtm.c += -mrtm +@@ -106,6 +108,7 @@ CFLAGS-tst-strcpy-rtm.c += -mrtm + CFLAGS-tst-strlen-rtm.c += -mrtm + CFLAGS-tst-strncmp-rtm.c += -mrtm -Wno-error + CFLAGS-tst-strrchr-rtm.c += -mrtm ++CFLAGS-tst-wcsncmp-rtm.c += -mrtm -Wno-error + endif + + ifneq ($(enable-cet),no) +diff --git a/sysdeps/x86/tst-strncmp-rtm.c b/sysdeps/x86/tst-strncmp-rtm.c +index 4d0004b58a..4e9f094f39 100644 +--- a/sysdeps/x86/tst-strncmp-rtm.c ++++ b/sysdeps/x86/tst-strncmp-rtm.c +@@ -19,18 +19,32 @@ + #include + #include + ++#ifdef WIDE ++# define CHAR wchar_t ++# define MEMSET wmemset ++# define STRNCMP wcsncmp ++# define TEST_NAME wcsncmp ++#else /* !WIDE */ ++# define CHAR char ++# define MEMSET memset ++# define STRNCMP strncmp ++# define TEST_NAME strncmp ++#endif /* !WIDE */ ++ ++ ++ + #define LOOP 3000 + #define STRING_SIZE 1024 +-char string1[STRING_SIZE]; +-char string2[STRING_SIZE]; ++CHAR string1[STRING_SIZE]; ++CHAR string2[STRING_SIZE]; + + __attribute__ ((noinline, noclone)) + static int + prepare (void) + { +- memset (string1, 'a', STRING_SIZE - 1); +- memset (string2, 'a', STRING_SIZE - 1); +- if (strncmp (string1, string2, STRING_SIZE) == 0) ++ MEMSET (string1, 'a', STRING_SIZE - 1); ++ MEMSET (string2, 'a', STRING_SIZE - 1); ++ if (STRNCMP (string1, string2, STRING_SIZE) == 0) + return EXIT_SUCCESS; + else + return EXIT_FAILURE; +@@ -40,7 +54,7 @@ __attribute__ ((noinline, noclone)) + static int + function (void) + { +- if (strncmp (string1, string2, STRING_SIZE) == 0) ++ if (STRNCMP (string1, string2, STRING_SIZE) == 0) + return 0; + else + return 1; +@@ -50,7 +64,7 @@ __attribute__ ((noinline, noclone)) + static int + function_overflow (void) + { +- if (strncmp (string1, string2, SIZE_MAX) == 0) ++ if (STRNCMP (string1, string2, SIZE_MAX) == 0) + return 0; + else + return 1; +@@ -59,9 +73,9 @@ function_overflow (void) + static int + do_test (void) + { +- int status = do_test_1 ("strncmp", LOOP, prepare, function); ++ int status = do_test_1 (TEST_NAME, LOOP, prepare, function); + if (status != EXIT_SUCCESS) + return status; +- status = do_test_1 ("strncmp", LOOP, prepare, function_overflow); ++ status = do_test_1 (TEST_NAME, LOOP, prepare, function_overflow); + return status; + } +diff --git a/sysdeps/x86/tst-wcsncmp-rtm.c b/sysdeps/x86/tst-wcsncmp-rtm.c +new file mode 100644 +index 0000000000..bad3b86378 +--- /dev/null ++++ b/sysdeps/x86/tst-wcsncmp-rtm.c +@@ -0,0 +1,21 @@ ++/* Test case for wcsncmp inside a transactionally executing RTM region. ++ Copyright (C) 2022 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 ++ . */ ++ ++#define WIDE 1 ++#include ++#include "tst-strncmp-rtm.c" +-- +2.27.0 + diff --git a/x86-Use-CHECK_FEATURE_PRESENT-to-check-HLE-BZ-27398.patch b/x86-Use-CHECK_FEATURE_PRESENT-to-check-HLE-BZ-27398.patch new file mode 100644 index 0000000000000000000000000000000000000000..ecd4a4293f49ae23ce3b3a27f0cf252ff0d9f110 --- /dev/null +++ b/x86-Use-CHECK_FEATURE_PRESENT-to-check-HLE-BZ-27398.patch @@ -0,0 +1,29 @@ +From aa601d024424c40ae9a69b0c4e394a70ea0570c8 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Mon, 24 Jan 2022 19:33:43 -0800 +Subject: [PATCH] x86: Use CHECK_FEATURE_PRESENT to check HLE [BZ #27398] + +HLE is disabled on blacklisted CPUs. Use CHECK_FEATURE_PRESENT, instead +of CHECK_FEATURE_ACTIVE, to check HLE. + +(cherry picked from commit 501246c5e2dfcc278f0ebbdb72345cdd239521c7) +--- + sysdeps/x86/tst-cpu-features-supports.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sysdeps/x86/tst-cpu-features-supports.c b/sysdeps/x86/tst-cpu-features-supports.c +index 9d76e6bd3f..faa5091b78 100644 +--- a/sysdeps/x86/tst-cpu-features-supports.c ++++ b/sysdeps/x86/tst-cpu-features-supports.c +@@ -130,7 +130,7 @@ do_test (int argc, char **argv) + fails += CHECK_FEATURE_ACTIVE (gfni, GFNI); + #endif + #if __GNUC_PREREQ (11, 0) +- fails += CHECK_FEATURE_ACTIVE (hle, HLE); ++ fails += CHECK_FEATURE_PRESENT (hle, HLE); + fails += CHECK_FEATURE_PRESENT (ibt, IBT); + fails += CHECK_FEATURE_ACTIVE (lahf_lm, LAHF64_SAHF64); + fails += CHECK_FEATURE_PRESENT (lm, LM); +-- +2.27.0 + diff --git a/x86-fix-Autoconf-caching-of-instruction-support-chec.patch b/x86-fix-Autoconf-caching-of-instruction-support-chec.patch new file mode 100644 index 0000000000000000000000000000000000000000..d4117fa6a97f8d987e75c36899ec5786fcc6235b --- /dev/null +++ b/x86-fix-Autoconf-caching-of-instruction-support-chec.patch @@ -0,0 +1,178 @@ +From 0835c0f0bad351117154b815f34f8af19ea7e325 Mon Sep 17 00:00:00 2001 +From: Matt Whitlock +Date: Wed, 16 Jun 2021 23:40:47 -0400 +Subject: [PATCH] x86: fix Autoconf caching of instruction support checks [BZ + #27991] + +The Autoconf documentation for the AC_CACHE_CHECK macro states: + + The commands-to-set-it must have no side effects except for setting + the variable cache-id, see below. + +However, the tests for support of -msahf and -mmovbe were embedded in +the commands-to-set-it for lib_cv_include_x86_isa_level. This had the +consequence that libc_cv_have_x86_lahf_sahf and libc_cv_have_x86_movbe +were not defined whenever lib_cv_include_x86_isa_level was read from +cache. These variables' being undefined meant that their unquoted use +in later test expressions led to the 'test' built-in's misparsing its +arguments and emitting errors like "test: =: unexpected operator" or +"test: =: unary operator expected", depending on the particular shell. + +This commit refactors the tests for LAHF/SAHF and MOVBE instruction +support into their own AC_CACHE_CHECK macro invocations to obey the +rule that the commands-to-set-it must have no side effects other than +setting the variable named by cache-id. + +Signed-off-by: Matt Whitlock +Reviewed-by: Adhemerval Zanella +--- + sysdeps/x86/configure | 56 ++++++++++++++++++++++++++++++------------------ + sysdeps/x86/configure.ac | 34 +++++++++++++++-------------- + 2 files changed, 53 insertions(+), 37 deletions(-) + +diff --git a/sysdeps/x86/configure b/sysdeps/x86/configure +index ead1295..62676bb 100644 +--- a/sysdeps/x86/configure ++++ b/sysdeps/x86/configure +@@ -126,8 +126,6 @@ cat > conftest2.S <&5 + (eval $ac_try) 2>&5 +@@ -137,9 +135,22 @@ if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -nostartfiles -nostdlib -r -o conftest c + count=`LC_ALL=C $READELF -n conftest | grep NT_GNU_PROPERTY_TYPE_0 | wc -l` + if test "$count" = 1; then + libc_cv_include_x86_isa_level=yes +- cat > conftest.c <&5 ++$as_echo "$libc_cv_include_x86_isa_level" >&6; } ++if test $libc_cv_include_x86_isa_level = yes; then ++ $as_echo "#define INCLUDE_X86_ISA_LEVEL 1" >>confdefs.h ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LAHF/SAHF instruction support" >&5 ++$as_echo_n "checking for LAHF/SAHF instruction support... " >&6; } ++if ${libc_cv_have_x86_lahf_sahf+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ libc_cv_have_x86_lahf_sahf=no ++ if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -fverbose-asm -S -o - -x c /dev/null' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 + (eval $ac_try) 2>&5 + ac_status=$? +@@ -147,7 +158,20 @@ EOF + test $ac_status = 0; }; } | grep -q "\-msahf"; then + libc_cv_have_x86_lahf_sahf=yes + fi +- if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -fverbose-asm -S -o - conftest.c' ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_have_x86_lahf_sahf" >&5 ++$as_echo "$libc_cv_have_x86_lahf_sahf" >&6; } ++ if test $libc_cv_have_x86_lahf_sahf = yes; then ++ $as_echo "#define HAVE_X86_LAHF_SAHF 1" >>confdefs.h ++ ++ fi ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for MOVBE instruction support" >&5 ++$as_echo_n "checking for MOVBE instruction support... " >&6; } ++if ${libc_cv_have_x86_movbe+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ libc_cv_have_x86_movbe=no ++ if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -fverbose-asm -S -o - -x c /dev/null' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 + (eval $ac_try) 2>&5 + ac_status=$? +@@ -155,23 +179,13 @@ EOF + test $ac_status = 0; }; } | grep -q "\-mmovbe"; then + libc_cv_have_x86_movbe=yes + fi +- fi +-fi +-rm -f conftest* +-fi +-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_include_x86_isa_level" >&5 +-$as_echo "$libc_cv_include_x86_isa_level" >&6; } +-if test $libc_cv_include_x86_isa_level = yes; then +- $as_echo "#define INCLUDE_X86_ISA_LEVEL 1" >>confdefs.h +- + fi +-if test $libc_cv_have_x86_lahf_sahf = yes; then +- $as_echo "#define HAVE_X86_LAHF_SAHF 1" >>confdefs.h +- +-fi +-if test $libc_cv_have_x86_movbe = yes; then +- $as_echo "#define HAVE_X86_MOVBE 1" >>confdefs.h ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_have_x86_movbe" >&5 ++$as_echo "$libc_cv_have_x86_movbe" >&6; } ++ if test $libc_cv_have_x86_movbe = yes; then ++ $as_echo "#define HAVE_X86_MOVBE 1" >>confdefs.h + ++ fi + fi + config_vars="$config_vars + enable-x86-isa-level = $libc_cv_include_x86_isa_level" +diff --git a/sysdeps/x86/configure.ac b/sysdeps/x86/configure.ac +index bca97fd..04a12ab 100644 +--- a/sysdeps/x86/configure.ac ++++ b/sysdeps/x86/configure.ac +@@ -98,30 +98,32 @@ cat > conftest2.S < conftest.c < +Date: Mon, 17 Jan 2022 19:41:40 +0100 +Subject: [PATCH] x86: use default cache size if it cannot be determined [BZ + #28784] + +In some cases (e.g QEMU, non-Intel/AMD CPU) the cache information can +not be retrieved and the corresponding values are set to 0. + +Commit 2d651eb9265d ("x86: Move x86 processor cache info to +cpu_features") changed the behaviour in such case by defining the +__x86_shared_cache_size and __x86_data_cache_size variables to 0 instead +of using the default values. This cause an issue with the i686 SSE2 +optimized bzero/routine which assumes that the cache size is at least +128 bytes, and otherwise tries to zero/set the whole address space minus +128 bytes. + +Fix that by restoring the original code to only update +__x86_shared_cache_size and __x86_data_cache_size variables if the +corresponding cache sizes are not zero. + +Fixes bug 28784 +Fixes commit 2d651eb9265d + +Reviewed-by: H.J. Lu +--- + sysdeps/x86/cacheinfo.h | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/sysdeps/x86/cacheinfo.h b/sysdeps/x86/cacheinfo.h +index 4f91a1e98d..65132a9d19 100644 +--- a/sysdeps/x86/cacheinfo.h ++++ b/sysdeps/x86/cacheinfo.h +@@ -61,14 +61,20 @@ init_cacheinfo (void) + long int data = cpu_features->data_cache_size; + /* Round data cache size to multiple of 256 bytes. */ + data = data & ~255L; +- __x86_data_cache_size_half = data / 2; +- __x86_data_cache_size = data; ++ if (data > 0) ++ { ++ __x86_data_cache_size_half = data / 2; ++ __x86_data_cache_size = data; ++ } + + long int shared = cpu_features->shared_cache_size; + /* Round shared cache size to multiple of 256 bytes. */ + shared = shared & ~255L; +- __x86_shared_cache_size_half = shared / 2; +- __x86_shared_cache_size = shared; ++ if (shared > 0) ++ { ++ __x86_shared_cache_size_half = shared / 2; ++ __x86_shared_cache_size = shared; ++ } + + __x86_shared_non_temporal_threshold + = cpu_features->non_temporal_threshold; +-- +2.27.0 + diff --git a/x86_64-Simplify-elf_machine_-load_address-dynamic.patch b/x86_64-Simplify-elf_machine_-load_address-dynamic.patch new file mode 100644 index 0000000000000000000000000000000000000000..b411a64f2ab29b23bbe8f82083c4f72759a0c4b6 --- /dev/null +++ b/x86_64-Simplify-elf_machine_-load_address-dynamic.patch @@ -0,0 +1,55 @@ +From b37b75d269883a2c553bb7019a813094eb4e2dd1 Mon Sep 17 00:00:00 2001 +From: Fangrui Song +Date: Tue, 17 Aug 2021 10:45:57 -0700 +Subject: [PATCH] x86_64: Simplify elf_machine_{load_address,dynamic} + +and drop reliance on _GLOBAL_OFFSET_TABLE_[0] being the link-time +address of _DYNAMIC. &__ehdr_start is a better way to get the load address. + +Reviewed-by: H.J. Lu +--- + sysdeps/x86_64/dl-machine.h | 21 +++++++-------------- + 1 file changed, 7 insertions(+), 14 deletions(-) + +diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h +index a8596aa..ceee507 100644 +--- a/sysdeps/x86_64/dl-machine.h ++++ b/sysdeps/x86_64/dl-machine.h +@@ -35,27 +35,20 @@ elf_machine_matches_host (const ElfW(Ehdr) *ehdr) + } + + +-/* Return the link-time address of _DYNAMIC. Conveniently, this is the +- first element of the GOT. This must be inlined in a function which +- uses global data. */ ++/* Return the run-time load address of the shared object. */ + static inline ElfW(Addr) __attribute__ ((unused)) +-elf_machine_dynamic (void) ++elf_machine_load_address (void) + { +- /* This produces an IP-relative reloc which is resolved at link time. */ +- extern const ElfW(Addr) _GLOBAL_OFFSET_TABLE_[] attribute_hidden; +- return _GLOBAL_OFFSET_TABLE_[0]; ++ extern const ElfW(Ehdr) __ehdr_start attribute_hidden; ++ return (ElfW(Addr)) &__ehdr_start; + } + +- +-/* Return the run-time load address of the shared object. */ ++/* Return the link-time address of _DYNAMIC. */ + static inline ElfW(Addr) __attribute__ ((unused)) +-elf_machine_load_address (void) ++elf_machine_dynamic (void) + { +- /* Compute the difference between the runtime address of _DYNAMIC as seen +- by an IP-relative reference, and the link-time address found in the +- special unrelocated first GOT entry. */ + extern ElfW(Dyn) _DYNAMIC[] attribute_hidden; +- return (ElfW(Addr)) &_DYNAMIC - elf_machine_dynamic (); ++ return (ElfW(Addr)) _DYNAMIC - elf_machine_load_address (); + } + + /* Set up the loaded object described by L so its unrelocated PLT +-- +1.8.3.1 +