diff --git a/build-extra-libpthreadcond-so.patch b/compat-2.17-libpthreadcond-so.patch similarity index 45% rename from build-extra-libpthreadcond-so.patch rename to compat-2.17-libpthreadcond-so.patch index f3c8e7d6b39e5621c3f6de09613f4e28859eb6fc..b7c62fefb80e0046252d9b8b212e02225b97656c 100644 --- a/build-extra-libpthreadcond-so.patch +++ b/compat-2.17-libpthreadcond-so.patch @@ -1,52 +1,103 @@ -From 808cf7c45e187c1889867ac83d047abfdf81c7a3 Mon Sep 17 00:00:00 2001 -From: xuhuijie -Date: Fri, 14 Aug 2020 17:41:59 +0800 +commit a88c9263686012ca2a336379b7d66e59dea2b43b +Author: Ulrich Drepper +Date: Wed Feb 5 09:54:24 2003 +0000 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 + +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. + +This patch contains, but is not limited to, the following submissions: +a88c9263686,59ba27a63ad,9bc6103d046,5acf7263d52,7ce5c1640cb,3e976b962a8,5bd8a24966d + +During the evolution of glibc, many header files are changed. To ensure the stability +of libpthread-2.17, header files of earlier versions are used, such as lowlevellock.h, sysdep.h, +descr.h, and futex-internal.h,pthread-function.h,pthreadtypes-arch.h,no-cancel.h.etc. Of course, +there are some interface modifications, such as __pause_nocancel. --- - 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(+) + nptl_2_17/Makefile | 50 + + nptl_2_17/bits/pthreadtypes_2_17.h | 127 ++ + nptl_2_17/bits/thread-shared-types_2_17.h | 185 +++ + nptl_2_17/build_libpthread-2.17.so.sh | 10 + + nptl_2_17/cancellation_2_17.c | 102 ++ + nptl_2_17/cleanup_compat_2_17.c | 50 + + nptl_2_17/descr_2_17.h | 412 ++++++ + nptl_2_17/elision-conf_2_17.c | 137 ++ + nptl_2_17/elision-conf_2_17.h | 41 + + nptl_2_17/elision-lock_2_17.c | 107 ++ + nptl_2_17/elision-timed_2_17.c | 26 + + nptl_2_17/elision-trylock_2_17.c | 75 ++ + nptl_2_17/elision-unlock_2_17.c | 33 + + nptl_2_17/futex-internal_2_17.h | 263 ++++ + nptl_2_17/hle_2_17.h | 75 ++ + nptl_2_17/internaltypes_2_17.h | 179 +++ + nptl_2_17/kernel-features_2_17.h | 162 +++ + nptl_2_17/libpthread-2.17-aarch64.map | 8 + + nptl_2_17/libpthread-2.17-x86_64.map | 8 + + nptl_2_17/lll_timedlock_wait_2_17.c | 59 + + nptl_2_17/lowlevellock_2_17.c | 46 + + nptl_2_17/pthread-functions_2_17.h | 116 ++ + nptl_2_17/pthreadP_2_17.h | 714 ++++++++++ + nptl_2_17/pthread_2_17.h | 1162 +++++++++++++++++ + nptl_2_17/pthread_cond_broadcast_2_17.c | 98 ++ + 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 | 266 ++++ + nptl_2_17/pthread_cond_wait_2_17.c | 234 ++++ + 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 | 635 +++++++++ + nptl_2_17/pthread_mutex_unlock_2_17.c | 359 +++++ + .../nptl/bits/pthreadtypes-arch_2_17.h | 71 + + nptl_2_17/sysdeps/generic/sysdep_2_17.h | 97 ++ + nptl_2_17/sysdeps/nptl/futex-internal_2_17.h | 210 +++ + nptl_2_17/sysdeps/nptl/lowlevellock_2_17.h | 208 +++ + nptl_2_17/sysdeps/unix/sysdep_2_17.h | 148 +++ + .../unix/sysv/linux/aarch64/sysdep_2_17.h | 301 +++++ + .../unix/sysv/linux/generic/sysdep_2_17.h | 35 + + .../unix/sysv/linux/internal-signals_2_17.h | 91 ++ + .../unix/sysv/linux/lowlevellock-futex_2_17.h | 150 +++ + .../sysdeps/unix/sysv/linux/not-cancel_2_17.h | 93 ++ + .../sysdeps/unix/sysv/linux/sysdep_2_17.h | 68 + + .../unix/sysv/linux/x86_64/sysdep_2_17.h | 432 ++++++ + nptl_2_17/sysdeps/unix/x86_64/sysdep_2_17.h | 34 + + nptl_2_17/sysdeps/x86/sysdep_2_17.h | 104 ++ + .../x86_64/nptl/bits/pthreadtypes-arch_2_17.h | 106 ++ + nptl_2_17/sysdeps/x86_64/sysdep_2_17.h | 129 ++ + nptl_2_17/thread_db_2_17.h | 458 +++++++ + nptl_2_17/tpp_2_17.c | 195 +++ + nptl_2_17/vars_2_17.c | 43 + + 56 files changed, 9084 insertions(+) create mode 100644 nptl_2_17/Makefile 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/build_libpthread-2.17.so.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/descr_2_17.h + create mode 100644 nptl_2_17/elision-conf_2_17.c + create mode 100644 nptl_2_17/elision-conf_2_17.h + 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/futex-internal_2_17.h + create mode 100644 nptl_2_17/hle_2_17.h + 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/libpthread-2.17-aarch64.map + create mode 100644 nptl_2_17/libpthread-2.17-x86_64.map + create mode 100644 nptl_2_17/lll_timedlock_wait_2_17.c + create mode 100644 nptl_2_17/lowlevellock_2_17.c + create mode 100644 nptl_2_17/pthread-functions_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 @@ -62,4932 +113,9446 @@ https://sourceware.org/git/?p=glibc.git;a=commit;h=ed19993b5b0d05d62cc883571519a 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/sysdeps/aarch64/nptl/bits/pthreadtypes-arch_2_17.h + create mode 100644 nptl_2_17/sysdeps/generic/sysdep_2_17.h + create mode 100644 nptl_2_17/sysdeps/nptl/futex-internal_2_17.h + create mode 100644 nptl_2_17/sysdeps/nptl/lowlevellock_2_17.h + create mode 100644 nptl_2_17/sysdeps/unix/sysdep_2_17.h + create mode 100644 nptl_2_17/sysdeps/unix/sysv/linux/aarch64/sysdep_2_17.h + create mode 100644 nptl_2_17/sysdeps/unix/sysv/linux/generic/sysdep_2_17.h + create mode 100644 nptl_2_17/sysdeps/unix/sysv/linux/internal-signals_2_17.h + create mode 100644 nptl_2_17/sysdeps/unix/sysv/linux/lowlevellock-futex_2_17.h + create mode 100644 nptl_2_17/sysdeps/unix/sysv/linux/not-cancel_2_17.h + create mode 100644 nptl_2_17/sysdeps/unix/sysv/linux/sysdep_2_17.h + create mode 100644 nptl_2_17/sysdeps/unix/sysv/linux/x86_64/sysdep_2_17.h + create mode 100644 nptl_2_17/sysdeps/unix/x86_64/sysdep_2_17.h + create mode 100644 nptl_2_17/sysdeps/x86/sysdep_2_17.h + create mode 100644 nptl_2_17/sysdeps/x86_64/nptl/bits/pthreadtypes-arch_2_17.h + create mode 100644 nptl_2_17/sysdeps/x86_64/sysdep_2_17.h + create mode 100644 nptl_2_17/thread_db_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/Makefile b/nptl_2_17/Makefile +new file mode 100644 +index 00000000..4c66b2b6 +--- /dev/null ++++ b/nptl_2_17/Makefile +@@ -0,0 +1,50 @@ ++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_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 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 cancellation_2_17.os pthread_mutex_lock_2_17.os pthread_mutex_unlock_2_17.os tpp_2_17.os vars_2_17.os pthread_mutex_cond_lock_2_17.os lll_timedlock_wait_2_17.os lowlevellock_2_17.os ++ ++ifeq (x86_64, $(arch)) ++compile_obj += elision-lock_2_17.os elision-unlock_2_17.os elision-timed_2_17.os elision-trylock_2_17.os ++endif ++ ++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../. -I../nptl_2_17/sysdeps/$(arch)/nptl -I../nptl_2_17/sysdeps/nptl -I../nptl_2_17/sysdeps/unix/sysv/linux/$(arch) -I../nptl_2_17/sysdeps/unix/sysv/linux -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) ++ 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..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..497e6903 +--- /dev/null ++++ b/nptl_2_17/bits/thread-shared-types_2_17.h +@@ -0,0 +1,185 @@ ++/* 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 ++ ++/* 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/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/cancellation_2_17.c b/nptl_2_17/cancellation_2_17.c +new file mode 100644 +index 00000000..db299fec +--- /dev/null ++++ b/nptl_2_17/cancellation_2_17.c +@@ -0,0 +1,102 @@ ++/* 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 ++#include ++#include "pthreadP_2_17.h" ++#include ++#include ++#include "futex-internal_2_17.h" ++ ++/* 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. */ ++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; ++} ++ ++ ++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..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/descr_2_17.h b/nptl_2_17/descr_2_17.h +new file mode 100644 +index 00000000..5148c852 +--- /dev/null ++++ b/nptl_2_17/descr_2_17.h +@@ -0,0 +1,412 @@ ++/* 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 _DESCR_H ++#define _DESCR_H 1 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "thread_db_2_17.h" ++#include ++#include ++#include ++#include ++ ++#ifndef TCB_ALIGNMENT ++# define TCB_ALIGNMENT sizeof (double) ++#endif ++ ++ ++/* We keep thread specific data in a special data structure, a two-level ++ array. The top-level array contains pointers to dynamically allocated ++ arrays of a certain number of data pointers. So we can implement a ++ sparse array. Each dynamic second-level array has ++ PTHREAD_KEY_2NDLEVEL_SIZE ++ entries. This value shouldn't be too large. */ ++#define PTHREAD_KEY_2NDLEVEL_SIZE 32 ++ ++/* We need to address PTHREAD_KEYS_MAX key with PTHREAD_KEY_2NDLEVEL_SIZE ++ keys in each subarray. */ ++#define PTHREAD_KEY_1STLEVEL_SIZE \ ++ ((PTHREAD_KEYS_MAX + PTHREAD_KEY_2NDLEVEL_SIZE - 1) \ ++ / PTHREAD_KEY_2NDLEVEL_SIZE) ++ ++ ++ ++ ++/* Internal version of the buffer to store cancellation handler ++ information. */ ++struct pthread_unwind_buf ++{ ++ struct ++ { ++ __jmp_buf jmp_buf; ++ int mask_was_saved; ++ } cancel_jmp_buf[1]; ++ ++ union ++ { ++ /* This is the placeholder of the public version. */ ++ void *pad[4]; ++ ++ struct ++ { ++ /* Pointer to the previous cleanup buffer. */ ++ struct pthread_unwind_buf *prev; ++ ++ /* Backward compatibility: state of the old-style cleanup ++ handler at the time of the previous new-style cleanup handler ++ installment. */ ++ struct _pthread_cleanup_buffer *cleanup; ++ ++ /* Cancellation type before the push call. */ ++ int canceltype; ++ } data; ++ } priv; ++}; ++ ++ ++/* Opcodes and data types for communication with the signal handler to ++ change user/group IDs. */ ++struct xid_command ++{ ++ int syscall_no; ++ /* Enforce zero-extension for the pointer argument in ++ ++ int setgroups (size_t size, const gid_t *list); ++ ++ The kernel XID arguments are unsigned and do not require sign ++ extension. */ ++ unsigned long int id[3]; ++ volatile int cntr; ++ volatile int error; /* -1: no call yet, 0: success seen, >0: error seen. */ ++}; ++ ++ ++/* Data structure used by the kernel to find robust futexes. */ ++struct robust_list_head ++{ ++ void *list; ++ long int futex_offset; ++ void *list_op_pending; ++}; ++ ++ ++/* Data strcture used to handle thread priority protection. */ ++struct priority_protection_data ++{ ++ int priomax; ++ unsigned int priomap[]; ++}; ++ ++ ++/* Thread descriptor data structure. */ ++struct pthread ++{ ++ union ++ { ++#if !TLS_DTV_AT_TP ++ /* This overlaps the TCB as used for TLS without threads (see tls.h). */ ++ tcbhead_t header; ++#else ++ struct ++ { ++ /* multiple_threads is enabled either when the process has spawned at ++ least one thread or when a single-threaded process cancels itself. ++ This enables additional code to introduce locking before doing some ++ compare_and_exchange operations and also enable cancellation points. ++ The concepts of multiple threads and cancellation points ideally ++ should be separate, since it is not necessary for multiple threads to ++ have been created for cancellation points to be enabled, as is the ++ case is when single-threaded process cancels itself. ++ ++ Since enabling multiple_threads enables additional code in ++ cancellation points and compare_and_exchange operations, there is a ++ potential for an unneeded performance hit when it is enabled in a ++ single-threaded, self-canceling process. This is OK though, since a ++ single-threaded process will enable async cancellation only when it ++ looks to cancel itself and is hence going to end anyway. */ ++ int multiple_threads; ++ int gscope_flag; ++ } header; ++#endif ++ ++ /* This extra padding has no special purpose, and this structure layout ++ is private and subject to change without affecting the official ABI. ++ We just have it here in case it might be convenient for some ++ implementation-specific instrumentation hack or suchlike. */ ++ void *__padding[24]; ++ }; ++ ++ /* This descriptor's link on the `stack_used' or `__stack_user' list. */ ++ list_t list; ++ ++ /* Thread ID - which is also a 'is this thread descriptor (and ++ therefore stack) used' flag. */ ++ pid_t tid; ++ ++ /* Ununsed. */ ++ pid_t pid_ununsed; ++ ++ /* List of robust mutexes the thread is holding. */ ++#if __PTHREAD_MUTEX_HAVE_PREV ++ void *robust_prev; ++ struct robust_list_head robust_head; ++ ++ /* The list above is strange. It is basically a double linked list ++ but the pointer to the next/previous element of the list points ++ in the middle of the object, the __next element. Whenever ++ casting to __pthread_list_t we need to adjust the pointer ++ first. ++ These operations are effectively concurrent code in that the thread ++ can get killed at any point in time and the kernel takes over. Thus, ++ the __next elements are a kind of concurrent list and we need to ++ enforce using compiler barriers that the individual operations happen ++ in such a way that the kernel always sees a consistent list. The ++ backward links (ie, the __prev elements) are not used by the kernel. ++ FIXME We should use relaxed MO atomic operations here and signal fences ++ because this kind of concurrency is similar to synchronizing with a ++ signal handler. */ ++# define QUEUE_PTR_ADJUST (offsetof (__pthread_list_t, __next)) ++ ++# define ENQUEUE_MUTEX_BOTH(mutex, val) \ ++ do { \ ++ __pthread_list_t *next = (__pthread_list_t *) \ ++ ((((uintptr_t) THREAD_GETMEM (THREAD_SELF, robust_head.list)) & ~1ul) \ ++ - QUEUE_PTR_ADJUST); \ ++ next->__prev = (void *) &mutex->__data.__list.__next; \ ++ mutex->__data.__list.__next = THREAD_GETMEM (THREAD_SELF, \ ++ robust_head.list); \ ++ mutex->__data.__list.__prev = (void *) &THREAD_SELF->robust_head; \ ++ /* Ensure that the new list entry is ready before we insert it. */ \ ++ __asm ("" ::: "memory"); \ ++ THREAD_SETMEM (THREAD_SELF, robust_head.list, \ ++ (void *) (((uintptr_t) &mutex->__data.__list.__next) \ ++ | val)); \ ++ } while (0) ++# define DEQUEUE_MUTEX(mutex) \ ++ do { \ ++ __pthread_list_t *next = (__pthread_list_t *) \ ++ ((char *) (((uintptr_t) mutex->__data.__list.__next) & ~1ul) \ ++ - QUEUE_PTR_ADJUST); \ ++ next->__prev = mutex->__data.__list.__prev; \ ++ __pthread_list_t *prev = (__pthread_list_t *) \ ++ ((char *) (((uintptr_t) mutex->__data.__list.__prev) & ~1ul) \ ++ - QUEUE_PTR_ADJUST); \ ++ prev->__next = mutex->__data.__list.__next; \ ++ /* Ensure that we remove the entry from the list before we change the \ ++ __next pointer of the entry, which is read by the kernel. */ \ ++ __asm ("" ::: "memory"); \ ++ mutex->__data.__list.__prev = NULL; \ ++ mutex->__data.__list.__next = NULL; \ ++ } while (0) ++#else ++ union ++ { ++ __pthread_slist_t robust_list; ++ struct robust_list_head robust_head; ++ }; ++ ++# define ENQUEUE_MUTEX_BOTH(mutex, val) \ ++ do { \ ++ mutex->__data.__list.__next \ ++ = THREAD_GETMEM (THREAD_SELF, robust_list.__next); \ ++ /* Ensure that the new list entry is ready before we insert it. */ \ ++ __asm ("" ::: "memory"); \ ++ THREAD_SETMEM (THREAD_SELF, robust_list.__next, \ ++ (void *) (((uintptr_t) &mutex->__data.__list) | val)); \ ++ } while (0) ++# define DEQUEUE_MUTEX(mutex) \ ++ do { \ ++ __pthread_slist_t *runp = (__pthread_slist_t *) \ ++ (((uintptr_t) THREAD_GETMEM (THREAD_SELF, robust_list.__next)) & ~1ul); \ ++ if (runp == &mutex->__data.__list) \ ++ THREAD_SETMEM (THREAD_SELF, robust_list.__next, runp->__next); \ ++ else \ ++ { \ ++ __pthread_slist_t *next = (__pthread_slist_t *) \ ++ (((uintptr_t) runp->__next) & ~1ul); \ ++ while (next != &mutex->__data.__list) \ ++ { \ ++ runp = next; \ ++ next = (__pthread_slist_t *) (((uintptr_t) runp->__next) & ~1ul); \ ++ } \ ++ \ ++ runp->__next = next->__next; \ ++ /* Ensure that we remove the entry from the list before we change the \ ++ __next pointer of the entry, which is read by the kernel. */ \ ++ __asm ("" ::: "memory"); \ ++ mutex->__data.__list.__next = NULL; \ ++ } \ ++ } while (0) ++#endif ++#define ENQUEUE_MUTEX(mutex) ENQUEUE_MUTEX_BOTH (mutex, 0) ++#define ENQUEUE_MUTEX_PI(mutex) ENQUEUE_MUTEX_BOTH (mutex, 1) ++ ++ /* List of cleanup buffers. */ ++ struct _pthread_cleanup_buffer *cleanup; ++ ++ /* Unwind information. */ ++ struct pthread_unwind_buf *cleanup_jmp_buf; ++#define HAVE_CLEANUP_JMP_BUF ++ ++ /* Flags determining processing of cancellation. */ ++ int cancelhandling; ++ /* Bit set if cancellation is disabled. */ ++#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(value) \ ++ (((value) & (CANCELSTATE_BITMASK | CANCELED_BITMASK | EXITING_BITMASK \ ++ | CANCEL_RESTMASK | TERMINATED_BITMASK)) == CANCELED_BITMASK) ++#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)) ++ ++ /* Flags. Including those copied from the thread attribute. */ ++ int flags; ++ ++ /* We allocate one block of references here. This should be enough ++ to avoid allocating any memory dynamically for most applications. */ ++ struct pthread_key_data ++ { ++ /* Sequence number. 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; ++ ++ /* Data pointer. */ ++ void *data; ++ } specific_1stblock[PTHREAD_KEY_2NDLEVEL_SIZE]; ++ ++ /* Two-level array for the thread-specific data. */ ++ struct pthread_key_data *specific[PTHREAD_KEY_1STLEVEL_SIZE]; ++ ++ /* Flag which is set when specific data is set. */ ++ bool specific_used; ++ ++ /* True if events must be reported. */ ++ bool report_events; ++ ++ /* True if the user provided the stack. */ ++ bool user_stack; ++ ++ /* True if thread must stop at startup time. */ ++ bool stopped_start; ++ ++ /* The parent's cancel handling at the time of the pthread_create ++ call. This might be needed to undo the effects of a cancellation. */ ++ int parent_cancelhandling; ++ ++ /* Lock to synchronize access to the descriptor. */ ++ int lock; ++ ++ /* Lock for synchronizing setxid calls. */ ++ unsigned int setxid_futex; ++ ++#ifdef __x86_64__ ++ /* Offset of the CPU clock at start thread start time. */ ++ hp_timing_t cpuclock_offset; ++#endif ++ ++ /* If the thread waits to join another one the ID of the latter is ++ stored here. ++ ++ In case a thread is detached this field contains a pointer of the ++ TCB if the thread itself. This is something which cannot happen ++ in normal operation. */ ++ struct pthread *joinid; ++ /* Check whether a thread is detached. */ ++#define IS_DETACHED(pd) ((pd)->joinid == (pd)) ++ ++ /* The result of the thread function. */ ++ void *result; ++ ++ /* Scheduling parameters for the new thread. */ ++ struct sched_param schedparam; ++ int schedpolicy; ++ ++ /* Start position of the code to be executed and the argument passed ++ to the function. */ ++ void *(*start_routine) (void *); ++ void *arg; ++ ++ /* Debug state. */ ++ td_eventbuf_t eventbuf; ++ /* Next descriptor with a pending event. */ ++ struct pthread *nextevent; ++ ++ /* Machine-specific unwind info. */ ++ struct _Unwind_Exception exc; ++ ++ /* If nonzero, pointer to the area allocated for the stack and guard. */ ++ void *stackblock; ++ /* Size of the stackblock area including the guard. */ ++ size_t stackblock_size; ++ /* Size of the included guard area. */ ++ size_t guardsize; ++ /* This is what the user specified and what we will report. */ ++ size_t reported_guardsize; ++ ++ /* Thread Priority Protection data. */ ++ struct priority_protection_data *tpp; ++ ++ /* Resolver state. */ ++ struct __res_state res; ++ ++ /* Indicates whether is a C11 thread created by thrd_creat. */ ++ bool c11; ++ ++ /* This member must be last. */ ++ char end_padding[]; ++ ++#define PTHREAD_STRUCT_END_PADDING \ ++ (sizeof (struct pthread) - offsetof (struct pthread, end_padding)) ++} __attribute ((aligned (TCB_ALIGNMENT))); ++ ++ ++#endif /* descr.h */ +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..13dd985e +--- /dev/null ++++ b/nptl_2_17/elision-conf_2_17.c +@@ -0,0 +1,137 @@ ++/* 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 ++ ++# define TUNABLE_NAMESPACE elision ++# define TOP_NAMESPACE glibc ++#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-conf_2_17.h b/nptl_2_17/elision-conf_2_17.h +new file mode 100644 +index 00000000..9cd38962 +--- /dev/null ++++ b/nptl_2_17/elision-conf_2_17.h +@@ -0,0 +1,41 @@ ++/* elision-conf.h: 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 ++ . */ ++#ifndef _ELISION_CONF_H ++#define _ELISION_CONF_H 1 ++ ++#include ++#include ++ ++/* Should make sure there is no false sharing on this. */ ++ ++struct elision_config ++{ ++ int skip_lock_busy; ++ int skip_lock_internal_abort; ++ int retry_try_xbegin; ++ int skip_trylock_internal_abort; ++}; ++ ++extern struct elision_config __elision_aconf attribute_hidden; ++ ++extern int __pthread_force_elision attribute_hidden; ++ ++/* Tell the test suite to test elision for this architecture. */ ++#define HAVE_ELISION 1 ++ ++#endif +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..6eebde8a +--- /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_2_17.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..b103f9aa +--- /dev/null ++++ b/nptl_2_17/elision-timed_2_17.c +@@ -0,0 +1,26 @@ ++/* 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_2_17.h" ++#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..8ed92198 +--- /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 ++#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..20b658a8 +--- /dev/null ++++ b/nptl_2_17/elision-unlock_2_17.c +@@ -0,0 +1,33 @@ ++/* 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_2_17.h" ++#include "hle_2_17.h" ++ ++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/futex-internal_2_17.h b/nptl_2_17/futex-internal_2_17.h +new file mode 100644 +index 00000000..b0512da0 +--- /dev/null ++++ b/nptl_2_17/futex-internal_2_17.h +@@ -0,0 +1,263 @@ ++/* futex operations for glibc-internal use. Linux version. ++ Copyright (C) 2014-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 FUTEX_INTERNAL_H ++#define FUTEX_INTERNAL_H ++ ++#include ++#include ++#include ++#include ++ ++/* See sysdeps/nptl/futex-internal.h for documentation; this file only ++ contains Linux-specific comments. ++ ++ The Linux kernel treats provides absolute timeouts based on the ++ CLOCK_REALTIME clock and relative timeouts measured against the ++ CLOCK_MONOTONIC clock. ++ ++ We expect a Linux kernel version of 2.6.22 or more recent (since this ++ version, EINTR is not returned on spurious wake-ups anymore). */ ++ ++/* FUTEX_SHARED is always supported by the Linux kernel. */ ++static __always_inline int ++futex_supports_pshared (int pshared) ++{ ++ if (__glibc_likely (pshared == PTHREAD_PROCESS_PRIVATE)) ++ return 0; ++ else if (pshared == PTHREAD_PROCESS_SHARED) ++ return 0; ++ else ++ return EINVAL; ++} ++ ++/* The Linux kernel supports relative timeouts measured against the ++ CLOCK_MONOTONIC clock. */ ++static __always_inline bool ++futex_supports_exact_relative_timeouts (void) ++{ ++ return true; ++} ++ ++/* See sysdeps/nptl/futex-internal.h for details. */ ++static __always_inline int ++futex_wait (unsigned int *futex_word, unsigned int expected, int private) ++{ ++ int err = lll_futex_timed_wait (futex_word, expected, NULL, private); ++ switch (err) ++ { ++ case 0: ++ case -EAGAIN: ++ case -EINTR: ++ return -err; ++ ++ case -ETIMEDOUT: /* Cannot have happened as we provided no timeout. */ ++ case -EFAULT: /* Must have been caused by a glibc or application bug. */ ++ case -EINVAL: /* Either due to wrong alignment or due to the timeout not ++ being normalized. Must have been caused by a glibc or ++ application bug. */ ++ case -ENOSYS: /* Must have been caused by a glibc bug. */ ++ /* No other errors are documented at this time. */ ++ default: ++ futex_fatal_error (); ++ } ++} ++ ++/* See sysdeps/nptl/futex-internal.h for details. */ ++static __always_inline int ++futex_wait_cancelable (unsigned int *futex_word, unsigned int expected, ++ int private) ++{ ++ int oldtype; ++ oldtype = __pthread_enable_asynccancel (); ++ int err = lll_futex_timed_wait (futex_word, expected, NULL, private); ++ __pthread_disable_asynccancel (oldtype); ++ switch (err) ++ { ++ case 0: ++ case -EAGAIN: ++ case -EINTR: ++ return -err; ++ ++ case -ETIMEDOUT: /* Cannot have happened as we provided no timeout. */ ++ case -EFAULT: /* Must have been caused by a glibc or application bug. */ ++ case -EINVAL: /* Either due to wrong alignment or due to the timeout not ++ being normalized. Must have been caused by a glibc or ++ application bug. */ ++ case -ENOSYS: /* Must have been caused by a glibc bug. */ ++ /* No other errors are documented at this time. */ ++ default: ++ futex_fatal_error (); ++ } ++} ++ ++/* See sysdeps/nptl/futex-internal.h for details. */ ++static __always_inline int ++futex_reltimed_wait (unsigned int *futex_word, unsigned int expected, ++ const struct timespec *reltime, int private) ++{ ++ int err = lll_futex_timed_wait (futex_word, expected, reltime, private); ++ switch (err) ++ { ++ case 0: ++ case -EAGAIN: ++ case -EINTR: ++ case -ETIMEDOUT: ++ return -err; ++ ++ case -EFAULT: /* Must have been caused by a glibc or application bug. */ ++ case -EINVAL: /* Either due to wrong alignment or due to the timeout not ++ being normalized. Must have been caused by a glibc or ++ application bug. */ ++ case -ENOSYS: /* Must have been caused by a glibc bug. */ ++ /* No other errors are documented at this time. */ ++ default: ++ futex_fatal_error (); ++ } ++} ++ ++/* See sysdeps/nptl/futex-internal.h for details. */ ++static __always_inline int ++futex_reltimed_wait_cancelable (unsigned int *futex_word, ++ unsigned int expected, ++ const struct timespec *reltime, int private) ++{ ++ int oldtype; ++ oldtype = __pthread_enable_asynccancel (); ++ int err = lll_futex_timed_wait (futex_word, expected, reltime, private); ++ __pthread_disable_asynccancel (oldtype); ++ switch (err) ++ { ++ case 0: ++ case -EAGAIN: ++ case -EINTR: ++ case -ETIMEDOUT: ++ return -err; ++ ++ case -EFAULT: /* Must have been caused by a glibc or application bug. */ ++ case -EINVAL: /* Either due to wrong alignment or due to the timeout not ++ being normalized. Must have been caused by a glibc or ++ application bug. */ ++ case -ENOSYS: /* Must have been caused by a glibc bug. */ ++ /* No other errors are documented at this time. */ ++ default: ++ futex_fatal_error (); ++ } ++} ++ ++/* See sysdeps/nptl/futex-internal.h for details. */ ++static __always_inline int ++futex_abstimed_supported_clockid (clockid_t clockid) ++{ ++ return lll_futex_supported_clockid (clockid); ++} ++ ++/* See sysdeps/nptl/futex-internal.h for details. */ ++static __always_inline int ++futex_abstimed_wait (unsigned int *futex_word, unsigned int expected, ++ clockid_t clockid, ++ const struct timespec *abstime, int private) ++{ ++ /* Work around the fact that the kernel rejects negative timeout values ++ despite them being valid. */ ++ if (__glibc_unlikely ((abstime != NULL) && (abstime->tv_sec < 0))) ++ return ETIMEDOUT; ++ int err = lll_futex_clock_wait_bitset (futex_word, expected, ++ clockid, abstime, ++ private); ++ switch (err) ++ { ++ case 0: ++ case -EAGAIN: ++ case -EINTR: ++ case -ETIMEDOUT: ++ return -err; ++ ++ case -EFAULT: /* Must have been caused by a glibc or application bug. */ ++ case -EINVAL: /* Either due to wrong alignment, unsupported ++ clockid or due to the timeout not being ++ normalized. Must have been caused by a glibc or ++ application bug. */ ++ case -ENOSYS: /* Must have been caused by a glibc bug. */ ++ /* No other errors are documented at this time. */ ++ default: ++ futex_fatal_error (); ++ } ++} ++ ++/* See sysdeps/nptl/futex-internal.h for details. */ ++static __always_inline int ++futex_abstimed_wait_cancelable (unsigned int *futex_word, ++ unsigned int expected, ++ clockid_t clockid, ++ const struct timespec *abstime, int private) ++{ ++ /* Work around the fact that the kernel rejects negative timeout values ++ despite them being valid. */ ++ if (__glibc_unlikely ((abstime != NULL) && (abstime->tv_sec < 0))) ++ return ETIMEDOUT; ++ int oldtype; ++ oldtype = __pthread_enable_asynccancel (); ++ int err = lll_futex_clock_wait_bitset (futex_word, expected, ++ clockid, abstime, ++ private); ++ __pthread_disable_asynccancel (oldtype); ++ switch (err) ++ { ++ case 0: ++ case -EAGAIN: ++ case -EINTR: ++ case -ETIMEDOUT: ++ return -err; ++ ++ case -EFAULT: /* Must have been caused by a glibc or application bug. */ ++ case -EINVAL: /* Either due to wrong alignment or due to the timeout not ++ being normalized. Must have been caused by a glibc or ++ application bug. */ ++ case -ENOSYS: /* Must have been caused by a glibc bug. */ ++ /* No other errors are documented at this time. */ ++ default: ++ futex_fatal_error (); ++ } ++} ++ ++/* See sysdeps/nptl/futex-internal.h for details. */ ++static __always_inline void ++futex_wake (unsigned int *futex_word, int processes_to_wake, int private) ++{ ++ int res = lll_futex_wake (futex_word, processes_to_wake, private); ++ /* No error. Ignore the number of woken processes. */ ++ if (res >= 0) ++ return; ++ switch (res) ++ { ++ case -EFAULT: /* Could have happened due to memory reuse. */ ++ case -EINVAL: /* Could be either due to incorrect alignment (a bug in ++ glibc or in the application) or due to memory being ++ reused for a PI futex. We cannot distinguish between the ++ two causes, and one of them is correct use, so we do not ++ act in this case. */ ++ return; ++ case -ENOSYS: /* Must have been caused by a glibc bug. */ ++ /* No other errors are documented at this time. */ ++ default: ++ futex_fatal_error (); ++ } ++} ++ ++#endif /* futex-internal.h */ +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 +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/libpthread-2.17-aarch64.map b/nptl_2_17/libpthread-2.17-aarch64.map +new file mode 100644 +index 00000000..d970af06 +--- /dev/null ++++ b/nptl_2_17/libpthread-2.17-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/libpthread-2.17-x86_64.map b/nptl_2_17/libpthread-2.17-x86_64.map +new file mode 100644 +index 00000000..d7f23322 +--- /dev/null ++++ b/nptl_2_17/libpthread-2.17-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/lll_timedlock_wait_2_17.c b/nptl_2_17/lll_timedlock_wait_2_17.c +new file mode 100644 +index 00000000..45ca994e +--- /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/lowlevellock_2_17.c b/nptl_2_17/lowlevellock_2_17.c +new file mode 100644 +index 00000000..9bbcc924 +--- /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. */ ++} +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..9e2a79f5 +--- /dev/null ++++ b/nptl_2_17/pthread-functions_2_17.h +@@ -0,0 +1,116 @@ ++/* 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_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 */ +diff --git a/nptl_2_17/pthreadP_2_17.h b/nptl_2_17/pthreadP_2_17.h +new file mode 100644 +index 00000000..ee1488c0 +--- /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 "kernel-features_2_17.h" ++#include "pthread_2_17.h" ++#include ++#include "internaltypes_2_17.h" ++#include ++#include "descr_2_17.h" ++#include ++ ++#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__)) ++#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)); ++} ++ ++ ++/* Set cancellation mode to asynchronous. */ ++#define CANCEL_ASYNC() \ ++ __pthread_enable_asynccancel () ++/* Reset to previous cancellation mode. */ ++#define CANCEL_RESET(oldtype) \ ++ __pthread_disable_asynccancel (oldtype) ++ ++# ifdef LIBC_CANCEL_ASYNC ++# undef LIBC_CANCEL_ASYNC ++# define LIBC_CANCEL_ASYNC() CANCEL_ASYNC () ++# endif ++# ifdef LIBC_CANCEL_RESET ++# undef LIBC_CANCEL_RESET ++# define LIBC_CANCEL_RESET(val) CANCEL_RESET (val) ++# endif ++# 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_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..f2d9c226 +--- /dev/null ++++ b/nptl_2_17/pthread_2_17.h +@@ -0,0 +1,1162 @@ ++/* 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)); ++ ++/* 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..d9b68f79 +--- /dev/null ++++ b/nptl_2_17/pthread_cond_broadcast_2_17.c +@@ -0,0 +1,98 @@ ++/* 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 ++ ++/* 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..f5bd7ade +--- /dev/null ++++ b/nptl_2_17/pthread_cond_destroy_2_17.c +@@ -0,0 +1,85 @@ ++/* 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_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..f4eff6ab +--- /dev/null ++++ b/nptl_2_17/pthread_cond_init_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 ++#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..5d79b894 +--- /dev/null ++++ b/nptl_2_17/pthread_cond_signal_2_17.c +@@ -0,0 +1,82 @@ ++/* 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 ++ ++ ++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..ab497195 +--- /dev/null ++++ b/nptl_2_17/pthread_cond_timedwait_2_17.c +@@ -0,0 +1,266 @@ ++/* 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 "kernel-features_2_17.h" ++#include "bits/thread-shared-types_2_17.h" ++#include ++#include "pthread_2_17.h" ++#include "pthreadP_2_17.h" ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++# undef INTERNAL_VSYSCALL ++# define INTERNAL_VSYSCALL INTERNAL_SYSCALL ++# undef INLINE_VSYSCALL ++# define INLINE_VSYSCALL INLINE_SYSCALL ++ ++/* 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..966ecab1 +--- /dev/null ++++ b/nptl_2_17/pthread_cond_wait_2_17.c +@@ -0,0 +1,234 @@ ++/* 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 "bits/thread-shared-types_2_17.h" ++#include ++#include ++#include "kernel-features_2_17.h" ++#include "pthread_2_17.h" ++#include "pthreadP_2_17.h" ++ ++#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..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..427a349c +--- /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..674ae77b +--- /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..787f37b0 +--- /dev/null ++++ b/nptl_2_17/pthread_mutex_lock_2_17.c +@@ -0,0 +1,635 @@ ++/* 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 ++ ++#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 (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, __err, 4, &mutex->__data.__lock, ++ __lll_private_flag (FUTEX_LOCK_PI, ++ private), 1, 0); ++ ++ if (INTERNAL_SYSCALL_ERROR_P (e, __err) ++ && (INTERNAL_SYSCALL_ERRNO (e, __err) == ESRCH ++ || INTERNAL_SYSCALL_ERRNO (e, __err) == EDEADLK)) ++ { ++ assert (INTERNAL_SYSCALL_ERRNO (e, __err) != 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 (); ++ } ++ ++ 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, __err, 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..cca86029 +--- /dev/null ++++ b/nptl_2_17/pthread_mutex_unlock_2_17.c +@@ -0,0 +1,359 @@ ++/* 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 ++ ++#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, __err, 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/sysdeps/aarch64/nptl/bits/pthreadtypes-arch_2_17.h b/nptl_2_17/sysdeps/aarch64/nptl/bits/pthreadtypes-arch_2_17.h +new file mode 100644 +index 00000000..008aa7e0 +--- /dev/null ++++ b/nptl_2_17/sysdeps/aarch64/nptl/bits/pthreadtypes-arch_2_17.h +@@ -0,0 +1,71 @@ ++/* 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 _BITS_PTHREADTYPES_ARCH_H ++#define _BITS_PTHREADTYPES_ARCH_H 1 ++ ++#include ++ ++#ifdef __ILP32__ ++# define __SIZEOF_PTHREAD_ATTR_T 32 ++# define __SIZEOF_PTHREAD_MUTEX_T 32 ++# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 ++# define __SIZEOF_PTHREAD_CONDATTR_T 4 ++# define __SIZEOF_PTHREAD_RWLOCK_T 48 ++# define __SIZEOF_PTHREAD_BARRIER_T 20 ++# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 ++#else ++# define __SIZEOF_PTHREAD_ATTR_T 64 ++# define __SIZEOF_PTHREAD_MUTEX_T 48 ++# define __SIZEOF_PTHREAD_MUTEXATTR_T 8 ++# define __SIZEOF_PTHREAD_CONDATTR_T 8 ++# define __SIZEOF_PTHREAD_RWLOCK_T 56 ++# define __SIZEOF_PTHREAD_BARRIER_T 32 ++# define __SIZEOF_PTHREAD_BARRIERATTR_T 8 ++#endif ++#define __SIZEOF_PTHREAD_COND_T 48 ++#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 ++ ++/* Definitions for internal mutex struct. */ ++#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 ++ ++#define __LOCK_ALIGNMENT ++#define __ONCE_ALIGNMENT ++ ++struct __pthread_rwlock_arch_t ++{ ++ unsigned int __readers; ++ unsigned int __writers; ++ unsigned int __wrphase_futex; ++ unsigned int __writers_futex; ++ unsigned int __pad3; ++ unsigned int __pad4; ++ int __cur_writer; ++ int __shared; ++ unsigned long int __pad1; ++ unsigned long int __pad2; ++ unsigned int __flags; ++}; ++ ++#define __PTHREAD_RWLOCK_ELISION_EXTRA 0 ++ ++#endif /* bits/pthreadtypes.h */ +diff --git a/nptl_2_17/sysdeps/generic/sysdep_2_17.h b/nptl_2_17/sysdeps/generic/sysdep_2_17.h +new file mode 100644 +index 00000000..934d4da8 +--- /dev/null ++++ b/nptl_2_17/sysdeps/generic/sysdep_2_17.h +@@ -0,0 +1,97 @@ ++/* Generic asm macros used on many machines. ++ Copyright (C) 1991-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 C_LABEL ++ ++/* Define a macro we can use to construct the asm name for a C symbol. */ ++# define C_LABEL(name) name##: ++ ++#endif ++ ++#ifdef __ASSEMBLER__ ++/* Mark the end of function named SYM. This is used on some platforms ++ to generate correct debugging information. */ ++# ifndef END ++# define END(sym) ++# endif ++ ++# ifndef JUMPTARGET ++# define JUMPTARGET(sym) sym ++# endif ++#endif ++ ++/* Makros to generate eh_frame unwind information. */ ++#ifdef __ASSEMBLER__ ++# define cfi_startproc .cfi_startproc ++# define cfi_endproc .cfi_endproc ++# define cfi_def_cfa(reg, off) .cfi_def_cfa reg, off ++# define cfi_def_cfa_register(reg) .cfi_def_cfa_register reg ++# define cfi_def_cfa_offset(off) .cfi_def_cfa_offset off ++# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off ++# define cfi_offset(reg, off) .cfi_offset reg, off ++# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off ++# define cfi_register(r1, r2) .cfi_register r1, r2 ++# define cfi_return_column(reg) .cfi_return_column reg ++# define cfi_restore(reg) .cfi_restore reg ++# define cfi_same_value(reg) .cfi_same_value reg ++# define cfi_undefined(reg) .cfi_undefined reg ++# define cfi_remember_state .cfi_remember_state ++# define cfi_restore_state .cfi_restore_state ++# define cfi_window_save .cfi_window_save ++# define cfi_personality(enc, exp) .cfi_personality enc, exp ++# define cfi_lsda(enc, exp) .cfi_lsda enc, exp ++ ++#else /* ! ASSEMBLER */ ++ ++# define CFI_STRINGIFY(Name) CFI_STRINGIFY2 (Name) ++# define CFI_STRINGIFY2(Name) #Name ++# define CFI_STARTPROC ".cfi_startproc" ++# define CFI_ENDPROC ".cfi_endproc" ++# define CFI_DEF_CFA(reg, off) \ ++ ".cfi_def_cfa " CFI_STRINGIFY(reg) "," CFI_STRINGIFY(off) ++# define CFI_DEF_CFA_REGISTER(reg) \ ++ ".cfi_def_cfa_register " CFI_STRINGIFY(reg) ++# define CFI_DEF_CFA_OFFSET(off) \ ++ ".cfi_def_cfa_offset " CFI_STRINGIFY(off) ++# define CFI_ADJUST_CFA_OFFSET(off) \ ++ ".cfi_adjust_cfa_offset " CFI_STRINGIFY(off) ++# define CFI_OFFSET(reg, off) \ ++ ".cfi_offset " CFI_STRINGIFY(reg) "," CFI_STRINGIFY(off) ++# define CFI_REL_OFFSET(reg, off) \ ++ ".cfi_rel_offset " CFI_STRINGIFY(reg) "," CFI_STRINGIFY(off) ++# define CFI_REGISTER(r1, r2) \ ++ ".cfi_register " CFI_STRINGIFY(r1) "," CFI_STRINGIFY(r2) ++# define CFI_RETURN_COLUMN(reg) \ ++ ".cfi_return_column " CFI_STRINGIFY(reg) ++# define CFI_RESTORE(reg) \ ++ ".cfi_restore " CFI_STRINGIFY(reg) ++# define CFI_UNDEFINED(reg) \ ++ ".cfi_undefined " CFI_STRINGIFY(reg) ++# define CFI_REMEMBER_STATE \ ++ ".cfi_remember_state" ++# define CFI_RESTORE_STATE \ ++ ".cfi_restore_state" ++# define CFI_WINDOW_SAVE \ ++ ".cfi_window_save" ++# define CFI_PERSONALITY(enc, exp) \ ++ ".cfi_personality " CFI_STRINGIFY(enc) "," CFI_STRINGIFY(exp) ++# define CFI_LSDA(enc, exp) \ ++ ".cfi_lsda " CFI_STRINGIFY(enc) "," CFI_STRINGIFY(exp) ++#endif ++ ++#include "dwarf2.h" +diff --git a/nptl_2_17/sysdeps/nptl/futex-internal_2_17.h b/nptl_2_17/sysdeps/nptl/futex-internal_2_17.h +new file mode 100644 +index 00000000..353fdfb9 +--- /dev/null ++++ b/nptl_2_17/sysdeps/nptl/futex-internal_2_17.h +@@ -0,0 +1,210 @@ ++/* futex operations for glibc-internal use. Stub version; do not include ++ this file directly. ++ Copyright (C) 2014-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 STUB_FUTEX_INTERNAL_H ++#define STUB_FUTEX_INTERNAL_H ++ ++#include ++#include ++#include ++#include ++ ++/* This file defines futex operations used internally in glibc. A futex ++ consists of the so-called futex word in userspace, which is of type ++ unsigned int and represents an application-specific condition, and kernel ++ state associated with this particular futex word (e.g., wait queues). The ++ futex operations we provide are wrappers for the futex syscalls and add ++ glibc-specific error checking of the syscall return value. We abort on ++ error codes that are caused by bugs in glibc or in the calling application, ++ or when an error code is not known. We return error codes that can arise ++ in correct executions to the caller. Each operation calls out exactly the ++ return values that callers need to handle. ++ ++ The private flag must be either FUTEX_PRIVATE or FUTEX_SHARED. ++ FUTEX_PRIVATE is always supported, and the implementation can internally ++ use FUTEX_SHARED when FUTEX_PRIVATE is requested. FUTEX_SHARED is not ++ necessarily supported (use futex_supports_pshared to detect this). ++ ++ We expect callers to only use these operations if futexes and the ++ specific futex operations being used are supported (e.g., FUTEX_SHARED). ++ ++ Given that waking other threads waiting on a futex involves concurrent ++ accesses to the futex word, you must use atomic operations to access the ++ futex word. ++ ++ Both absolute and relative timeouts can be used. An absolute timeout ++ expires when the given specific point in time on the specified clock ++ passes, or when it already has passed. A relative timeout expires when ++ the given duration of time on the CLOCK_MONOTONIC clock passes. Relative ++ timeouts may be imprecise (see futex_supports_exact_relative_timeouts). ++ ++ Due to POSIX requirements on when synchronization data structures such ++ as mutexes or semaphores can be destroyed and due to the futex design ++ having separate fast/slow paths for wake-ups, we need to consider that ++ futex_wake calls might effectively target a data structure that has been ++ destroyed and reused for another object, or unmapped; thus, some ++ errors or spurious wake-ups can happen in correct executions that would ++ not be possible in a program using just a single futex whose lifetime ++ does not end before the program terminates. For background, see: ++ https://sourceware.org/ml/libc-alpha/2014-04/msg00075.html ++ https://lkml.org/lkml/2014/11/27/472 */ ++ ++/* Defined this way for interoperability with lowlevellock. ++ FUTEX_PRIVATE must be zero because the initializers for pthread_mutex_t, ++ pthread_rwlock_t, and pthread_cond_t initialize the respective field of ++ those structures to zero, and we want FUTEX_PRIVATE to be the default. */ ++#define FUTEX_PRIVATE LLL_PRIVATE ++#define FUTEX_SHARED LLL_SHARED ++#if FUTEX_PRIVATE != 0 ++# error FUTEX_PRIVATE must be equal to 0 ++#endif ++ ++/* Returns EINVAL if PSHARED is neither PTHREAD_PROCESS_PRIVATE nor ++ PTHREAD_PROCESS_SHARED; otherwise, returns 0 if PSHARED is supported, and ++ ENOTSUP if not. */ ++static __always_inline int ++futex_supports_pshared (int pshared); ++ ++/* Returns true if relative timeouts are robust to concurrent changes to the ++ system clock. If this returns false, relative timeouts can still be used ++ but might be effectively longer or shorter than requested. */ ++static __always_inline bool ++futex_supports_exact_relative_timeouts (void); ++ ++/* Atomically wrt other futex operations on the same futex, this blocks iff ++ the value *FUTEX_WORD matches the expected value. This is ++ semantically equivalent to: ++ l = (FUTEX_WORD); ++ wait_flag = (FUTEX_WORD); ++ lock (l); ++ val = atomic_load_relaxed (FUTEX_WORD); ++ if (val != expected) { unlock (l); return EAGAIN; } ++ atomic_store_relaxed (wait_flag, true); ++ unlock (l); ++ // Now block; can time out in futex_time_wait (see below) ++ while (atomic_load_relaxed(wait_flag) && !); ++ ++ Note that no guarantee of a happens-before relation between a woken ++ futex_wait and a futex_wake is documented; however, this does not matter ++ in practice because we have to consider spurious wake-ups (see below), ++ and thus would not be able to reliably reason about which futex_wake woke ++ us. ++ ++ Returns 0 if woken by a futex operation or spuriously. (Note that due to ++ the POSIX requirements mentioned above, we need to conservatively assume ++ that unrelated futex_wake operations could wake this futex; it is easiest ++ to just be prepared for spurious wake-ups.) ++ Returns EAGAIN if the futex word did not match the expected value. ++ Returns EINTR if waiting was interrupted by a signal. ++ ++ Note that some previous code in glibc assumed the underlying futex ++ operation (e.g., syscall) to start with or include the equivalent of a ++ seq_cst fence; this allows one to avoid an explicit seq_cst fence before ++ a futex_wait call when synchronizing similar to Dekker synchronization. ++ However, we make no such guarantee here. */ ++static __always_inline int ++futex_wait (unsigned int *futex_word, unsigned int expected, int private); ++ ++/* Like futex_wait but does not provide any indication why we stopped waiting. ++ Thus, when this function returns, you have to always check FUTEX_WORD to ++ determine whether you need to continue waiting, and you cannot detect ++ whether the waiting was interrupted by a signal. Example use: ++ while (atomic_load_relaxed (&futex_word) == 23) ++ futex_wait_simple (&futex_word, 23, FUTEX_PRIVATE); ++ This is common enough to make providing this wrapper worthwhile. */ ++static __always_inline void ++futex_wait_simple (unsigned int *futex_word, unsigned int expected, ++ int private) ++{ ++ ignore_value (futex_wait (futex_word, expected, private)); ++} ++ ++ ++/* Like futex_wait but is a POSIX cancellation point. */ ++static __always_inline int ++futex_wait_cancelable (unsigned int *futex_word, unsigned int expected, ++ int private); ++ ++/* Like futex_wait, but will eventually time out (i.e., stop being ++ blocked) after the duration of time provided (i.e., RELTIME) has ++ passed. The caller must provide a normalized RELTIME. RELTIME can also ++ equal NULL, in which case this function behaves equivalent to futex_wait. ++ ++ Returns the same values as futex_wait under those same conditions; ++ additionally, returns ETIMEDOUT if the timeout expired. ++ */ ++static __always_inline int ++futex_reltimed_wait (unsigned int* futex_word, unsigned int expected, ++ const struct timespec* reltime, int private); ++ ++/* Like futex_reltimed_wait but is a POSIX cancellation point. */ ++static __always_inline int ++futex_reltimed_wait_cancelable (unsigned int* futex_word, ++ unsigned int expected, ++ const struct timespec* reltime, int private); ++ ++/* Check whether the specified clockid is supported by ++ futex_abstimed_wait and futex_abstimed_wait_cancelable. */ ++static __always_inline int ++futex_abstimed_supported_clockid (clockid_t clockid); ++ ++/* Like futex_reltimed_wait, but the provided timeout (ABSTIME) is an ++ absolute point in time; a call will time out after this point in time. */ ++static __always_inline int ++futex_abstimed_wait (unsigned int* futex_word, unsigned int expected, ++ clockid_t clockid, ++ const struct timespec* abstime, int private); ++ ++/* Like futex_reltimed_wait but is a POSIX cancellation point. */ ++static __always_inline int ++futex_abstimed_wait_cancelable (unsigned int* futex_word, ++ unsigned int expected, ++ clockid_t clockid, ++ const struct timespec* abstime, int private); ++ ++/* Atomically wrt other futex operations on the same futex, this unblocks the ++ specified number of processes, or all processes blocked on this futex if ++ there are fewer than the specified number. Semantically, this is ++ equivalent to: ++ l = (FUTEX_WORD); ++ lock (l); ++ for (res = 0; PROCESSES_TO_WAKE > 0; PROCESSES_TO_WAKE--, res++) { ++ if () break; ++ wf = (FUTEX_WORD); ++ // No happens-before guarantee with woken futex_wait (see above) ++ atomic_store_relaxed (wf, 0); ++ } ++ return res; ++ ++ Note that we need to support futex_wake calls to past futexes whose memory ++ has potentially been reused due to POSIX' requirements on synchronization ++ object destruction (see above); therefore, we must not report or abort ++ on most errors. */ ++static __always_inline void ++futex_wake (unsigned int* futex_word, int processes_to_wake, int private); ++ ++/* Calls __libc_fatal with an error message. Convenience function for ++ concrete implementations of the futex interface. */ ++static __always_inline __attribute__ ((__noreturn__)) void ++futex_fatal_error (void) ++{ ++ __libc_fatal ("The futex facility returned an unexpected error code."); ++} ++ ++#endif /* futex-internal.h */ +diff --git a/nptl_2_17/sysdeps/nptl/lowlevellock_2_17.h b/nptl_2_17/sysdeps/nptl/lowlevellock_2_17.h +new file mode 100644 +index 00000000..1247949a +--- /dev/null ++++ b/nptl_2_17/sysdeps/nptl/lowlevellock_2_17.h +@@ -0,0 +1,208 @@ ++/* Low-level lock implementation. Generic futex-based version. ++ Copyright (C) 2005-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 _LOWLEVELLOCK_H ++#define _LOWLEVELLOCK_H 1 ++ ++#include ++#include ++ ++/* Low-level locks use a combination of atomic operations (to acquire and ++ release lock ownership) and futex operations (to block until the state ++ of a lock changes). A lock can be in one of three states: ++ 0: not acquired, ++ 1: acquired with no waiters; no other threads are blocked or about to block ++ for changes to the lock state, ++ >1: acquired, possibly with waiters; there may be other threads blocked or ++ about to block for changes to the lock state. ++ ++ We expect that the common case is an uncontended lock, so we just need ++ to transition the lock between states 0 and 1; releasing the lock does ++ not need to wake any other blocked threads. If the lock is contended ++ and a thread decides to block using a futex operation, then this thread ++ needs to first change the state to >1; if this state is observed during ++ lock release, the releasing thread will wake one of the potentially ++ blocked threads. ++ ++ Much of this code takes a 'private' parameter. This may be: ++ LLL_PRIVATE: lock only shared within a process ++ LLL_SHARED: lock may be shared across processes. ++ ++ Condition variables contain an optimization for broadcasts that requeues ++ waiting threads on a lock's futex. Therefore, there is a special ++ variant of the locks (whose name contains "cond") that makes sure to ++ always set the lock state to >1 and not just 1. ++ ++ Robust locks set the lock to the id of the owner. This allows detection ++ of the case where the owner exits without releasing the lock. Flags are ++ OR'd with the owner id to record additional information about lock state. ++ Therefore the states of robust locks are: ++ 0: not acquired ++ id: acquired (by user identified by id & FUTEX_TID_MASK) ++ ++ The following flags may be set in the robust lock value: ++ FUTEX_WAITERS - possibly has waiters ++ FUTEX_OWNER_DIED - owning user has exited without releasing the futex. */ ++ ++ ++/* If LOCK is 0 (not acquired), set to 1 (acquired with no waiters) and return ++ 0. Otherwise leave lock unchanged and return non-zero to indicate that the ++ lock was not acquired. */ ++#define lll_trylock(lock) \ ++ __glibc_unlikely (atomic_compare_and_exchange_bool_acq (&(lock), 1, 0)) ++ ++/* If LOCK is 0 (not acquired), set to 2 (acquired, possibly with waiters) and ++ return 0. Otherwise leave lock unchanged and return non-zero to indicate ++ that the lock was not acquired. */ ++#define lll_cond_trylock(lock) \ ++ __glibc_unlikely (atomic_compare_and_exchange_bool_acq (&(lock), 2, 0)) ++ ++extern void __lll_lock_wait_private (int *futex) attribute_hidden; ++extern void __lll_lock_wait (int *futex, int private) attribute_hidden; ++ ++/* This is an expression rather than a statement even though its value is ++ void, so that it can be used in a comma expression or as an expression ++ that's cast to void. */ ++/* The inner conditional compiles to a call to __lll_lock_wait_private if ++ private is known at compile time to be LLL_PRIVATE, and to a call to ++ __lll_lock_wait otherwise. */ ++/* If FUTEX is 0 (not acquired), set to 1 (acquired with no waiters) and ++ return. Otherwise, ensure that it is >1 (acquired, possibly with waiters) ++ and then block until we acquire the lock, at which point FUTEX will still be ++ >1. The lock is always acquired on return. */ ++#define __lll_lock(futex, private) \ ++ ((void) \ ++ ({ \ ++ int *__futex = (futex); \ ++ if (__glibc_unlikely \ ++ (atomic_compare_and_exchange_bool_acq (__futex, 1, 0))) \ ++ { \ ++ if (__builtin_constant_p (private) && (private) == LLL_PRIVATE) \ ++ __lll_lock_wait_private (__futex); \ ++ else \ ++ __lll_lock_wait (__futex, private); \ ++ } \ ++ })) ++#define lll_lock(futex, private) \ ++ __lll_lock (&(futex), private) ++ ++ ++/* This is an expression rather than a statement even though its value is ++ void, so that it can be used in a comma expression or as an expression ++ that's cast to void. */ ++/* Unconditionally set FUTEX to 2 (acquired, possibly with waiters). If FUTEX ++ was 0 (not acquired) then return. Otherwise, block until the lock is ++ acquired, at which point FUTEX is 2 (acquired, possibly with waiters). The ++ lock is always acquired on return. */ ++#define __lll_cond_lock(futex, private) \ ++ ((void) \ ++ ({ \ ++ int *__futex = (futex); \ ++ if (__glibc_unlikely (atomic_exchange_acq (__futex, 2) != 0)) \ ++ __lll_lock_wait (__futex, private); \ ++ })) ++#define lll_cond_lock(futex, private) __lll_cond_lock (&(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) ++ ++ ++/* This is an expression rather than a statement even though its value is ++ void, so that it can be used in a comma expression or as an expression ++ that's cast to void. */ ++/* Unconditionally set FUTEX to 0 (not acquired), releasing the lock. If FUTEX ++ was >1 (acquired, possibly with waiters), then wake any waiters. The waiter ++ that acquires the lock will set FUTEX to >1. ++ Evaluate PRIVATE before releasing the lock so that we do not violate the ++ mutex destruction requirements. Specifically, we need to ensure that ++ another thread can destroy the mutex (and reuse its memory) once it ++ acquires the lock and when there will be no further lock acquisitions; ++ thus, we must not access the lock after releasing it, or those accesses ++ could be concurrent with mutex destruction or reuse of the memory. */ ++#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); \ ++ })) ++#define lll_unlock(futex, private) \ ++ __lll_unlock (&(futex), private) ++ ++ ++#define lll_islocked(futex) \ ++ ((futex) != LLL_LOCK_INITIALIZER) ++ ++ ++/* Our internal lock implementation is identical to the binary-compatible ++ mutex implementation. */ ++ ++/* Initializers for lock. */ ++#define LLL_LOCK_INITIALIZER (0) ++#define LLL_LOCK_INITIALIZER_LOCKED (1) ++ ++ ++/* The kernel notifies a process which uses CLONE_CHILD_CLEARTID via futex ++ wake-up when the clone terminates. The memory location contains the ++ thread ID while the clone is running and is reset to zero by the kernel ++ afterwards. The kernel up to version 3.16.3 does not use the private futex ++ operations for futex wake-up when the clone terminates. */ ++#define lll_wait_tid(tid) \ ++ do { \ ++ __typeof (tid) __tid; \ ++ /* We need acquire MO here so that we synchronize \ ++ with the kernel's store to 0 when the clone \ ++ terminates. (see above) */ \ ++ while ((__tid = atomic_load_acquire (&(tid))) != 0) \ ++ lll_futex_wait (&(tid), __tid, LLL_SHARED); \ ++ } while (0) ++ ++extern int __lll_timedwait_tid (int *, const struct timespec *) ++ attribute_hidden; ++ ++/* As lll_wait_tid, but with a timeout. If the timeout occurs then return ++ ETIMEDOUT. If ABSTIME is invalid, return EINVAL. */ ++#define lll_timedwait_tid(tid, abstime) \ ++ ({ \ ++ int __res = 0; \ ++ if ((tid) != 0) \ ++ __res = __lll_timedwait_tid (&(tid), (abstime)); \ ++ __res; \ ++ }) ++ ++ ++#endif /* lowlevellock.h */ +diff --git a/nptl_2_17/sysdeps/unix/sysdep_2_17.h b/nptl_2_17/sysdeps/unix/sysdep_2_17.h +new file mode 100644 +index 00000000..a9905ff9 +--- /dev/null ++++ b/nptl_2_17/sysdeps/unix/sysdep_2_17.h +@@ -0,0 +1,148 @@ ++/* Copyright (C) 1991-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 ++#define HAVE_SYSCALLS ++ ++/* Note that using a `PASTE' macro loses. */ ++#define SYSCALL__(name, args) PSEUDO (__##name, name, args) ++#define SYSCALL(name, args) PSEUDO (name, name, args) ++ ++#define __SYSCALL_CONCAT_X(a,b) a##b ++#define __SYSCALL_CONCAT(a,b) __SYSCALL_CONCAT_X (a, b) ++ ++ ++#define __INTERNAL_SYSCALL0(name, err) \ ++ INTERNAL_SYSCALL (name, err, 0) ++#define __INTERNAL_SYSCALL1(name, err, a1) \ ++ INTERNAL_SYSCALL (name, err, 1, a1) ++#define __INTERNAL_SYSCALL2(name, err, a1, a2) \ ++ INTERNAL_SYSCALL (name, err, 2, a1, a2) ++#define __INTERNAL_SYSCALL3(name, err, a1, a2, a3) \ ++ INTERNAL_SYSCALL (name, err, 3, a1, a2, a3) ++#define __INTERNAL_SYSCALL4(name, err, a1, a2, a3, a4) \ ++ INTERNAL_SYSCALL (name, err, 4, a1, a2, a3, a4) ++#define __INTERNAL_SYSCALL5(name, err, a1, a2, a3, a4, a5) \ ++ INTERNAL_SYSCALL (name, err, 5, a1, a2, a3, a4, a5) ++#define __INTERNAL_SYSCALL6(name, err, a1, a2, a3, a4, a5, a6) \ ++ INTERNAL_SYSCALL (name, err, 6, a1, a2, a3, a4, a5, a6) ++#define __INTERNAL_SYSCALL7(name, err, a1, a2, a3, a4, a5, a6, a7) \ ++ INTERNAL_SYSCALL (name, err, 7, a1, a2, a3, a4, a5, a6, a7) ++ ++#define __INTERNAL_SYSCALL_NARGS_X(a,b,c,d,e,f,g,h,n,o,...) o ++#define __INTERNAL_SYSCALL_NARGS(...) \ ++ __INTERNAL_SYSCALL_NARGS_X (__VA_ARGS__,7,6,5,4,3,2,1,0,) ++#define __INTERNAL_SYSCALL_DISP(b,...) \ ++ __SYSCALL_CONCAT (b,__INTERNAL_SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) ++ ++/* Issue a syscall defined by syscall number plus any other argument required. ++ It is similar to INTERNAL_SYSCALL macro, but without the need to pass the ++ expected argument number as second parameter. */ ++#define INTERNAL_SYSCALL_CALL(...) \ ++ __INTERNAL_SYSCALL_DISP (__INTERNAL_SYSCALL, __VA_ARGS__) ++ ++#define __INLINE_SYSCALL0(name) \ ++ INLINE_SYSCALL (name, 0) ++#define __INLINE_SYSCALL1(name, a1) \ ++ INLINE_SYSCALL (name, 1, a1) ++#define __INLINE_SYSCALL2(name, a1, a2) \ ++ INLINE_SYSCALL (name, 2, a1, a2) ++#define __INLINE_SYSCALL3(name, a1, a2, a3) \ ++ INLINE_SYSCALL (name, 3, a1, a2, a3) ++#define __INLINE_SYSCALL4(name, a1, a2, a3, a4) \ ++ INLINE_SYSCALL (name, 4, a1, a2, a3, a4) ++#define __INLINE_SYSCALL5(name, a1, a2, a3, a4, a5) \ ++ INLINE_SYSCALL (name, 5, a1, a2, a3, a4, a5) ++#define __INLINE_SYSCALL6(name, a1, a2, a3, a4, a5, a6) \ ++ INLINE_SYSCALL (name, 6, a1, a2, a3, a4, a5, a6) ++#define __INLINE_SYSCALL7(name, a1, a2, a3, a4, a5, a6, a7) \ ++ INLINE_SYSCALL (name, 7, a1, a2, a3, a4, a5, a6, a7) ++ ++#define __INLINE_SYSCALL_NARGS_X(a,b,c,d,e,f,g,h,n,...) n ++#define __INLINE_SYSCALL_NARGS(...) \ ++ __INLINE_SYSCALL_NARGS_X (__VA_ARGS__,7,6,5,4,3,2,1,0,) ++#define __INLINE_SYSCALL_DISP(b,...) \ ++ __SYSCALL_CONCAT (b,__INLINE_SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) ++ ++/* Issue a syscall defined by syscall number plus any other argument ++ required. Any error will be handled using arch defined macros and errno ++ will be set accordingly. ++ It is similar to INLINE_SYSCALL macro, but without the need to pass the ++ expected argument number as second parameter. */ ++#define INLINE_SYSCALL_CALL(...) \ ++ __INLINE_SYSCALL_DISP (__INLINE_SYSCALL, __VA_ARGS__) ++ ++#define SYSCALL_CANCEL(...) \ ++ ({ \ ++ long int sc_ret; \ ++ if (SINGLE_THREAD_P) \ ++ sc_ret = INLINE_SYSCALL_CALL (__VA_ARGS__); \ ++ else \ ++ { \ ++ int sc_cancel_oldtype = LIBC_CANCEL_ASYNC (); \ ++ sc_ret = INLINE_SYSCALL_CALL (__VA_ARGS__); \ ++ LIBC_CANCEL_RESET (sc_cancel_oldtype); \ ++ } \ ++ sc_ret; \ ++ }) ++ ++/* Issue a syscall defined by syscall number plus any other argument ++ required. Any error will be returned unmodified (including errno). */ ++#define INTERNAL_SYSCALL_CANCEL(...) \ ++ ({ \ ++ long int sc_ret; \ ++ if (SINGLE_THREAD_P) \ ++ sc_ret = INTERNAL_SYSCALL_CALL (__VA_ARGS__); \ ++ else \ ++ { \ ++ int sc_cancel_oldtype = LIBC_CANCEL_ASYNC (); \ ++ sc_ret = INTERNAL_SYSCALL_CALL (__VA_ARGS__); \ ++ LIBC_CANCEL_RESET (sc_cancel_oldtype); \ ++ } \ ++ sc_ret; \ ++ }) ++ ++/* Machine-dependent sysdep.h files are expected to define the macro ++ PSEUDO (function_name, syscall_name) to emit assembly code to define the ++ C-callable function FUNCTION_NAME to do system call SYSCALL_NAME. ++ r0 and r1 are the system call outputs. MOVE(x, y) should be defined as ++ an instruction such that "MOVE(r1, r0)" works. ret should be defined ++ as the return instruction. */ ++ ++#ifndef SYS_ify ++#define SYS_ify(syscall_name) SYS_##syscall_name ++#endif ++ ++/* Terminate a system call named SYM. This is used on some platforms ++ to generate correct debugging information. */ ++#ifndef PSEUDO_END ++#define PSEUDO_END(sym) ++#endif ++#ifndef PSEUDO_END_NOERRNO ++#define PSEUDO_END_NOERRNO(sym) PSEUDO_END(sym) ++#endif ++#ifndef PSEUDO_END_ERRVAL ++#define PSEUDO_END_ERRVAL(sym) PSEUDO_END(sym) ++#endif ++ ++/* Wrappers around system calls should normally inline the system call code. ++ But sometimes it is not possible or implemented and we use this code. */ ++#ifndef INLINE_SYSCALL ++#define INLINE_SYSCALL(name, nr, args...) __syscall_##name (args) ++#endif +diff --git a/nptl_2_17/sysdeps/unix/sysv/linux/aarch64/sysdep_2_17.h b/nptl_2_17/sysdeps/unix/sysv/linux/aarch64/sysdep_2_17.h +new file mode 100644 +index 00000000..76f41900 +--- /dev/null ++++ b/nptl_2_17/sysdeps/unix/sysv/linux/aarch64/sysdep_2_17.h +@@ -0,0 +1,301 @@ ++/* Copyright (C) 2005-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 _LINUX_AARCH64_SYSDEP_H ++#define _LINUX_AARCH64_SYSDEP_H 1 ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* Defines RTLD_PRIVATE_ERRNO and USE_DL_SYSINFO. */ ++#include ++ ++#include ++ ++/* In order to get __set_errno() definition in INLINE_SYSCALL. */ ++#ifndef __ASSEMBLER__ ++#include ++#endif ++ ++/* For Linux we can use the system call table in the header file ++ /usr/include/asm/unistd.h ++ of the kernel. But these symbols do not follow the SYS_* syntax ++ so we have to redefine the `SYS_ify' macro here. */ ++#undef SYS_ify ++#define SYS_ify(syscall_name) (__NR_##syscall_name) ++ ++#ifdef __ASSEMBLER__ ++ ++/* Linux uses a negative return value to indicate syscall errors, ++ unlike most Unices, which use the condition codes' carry flag. ++ ++ Since version 2.1 the return value of a system call might be ++ negative even if the call succeeded. E.g., the `lseek' system call ++ might return a large offset. Therefore we must not anymore test ++ for < 0, but test for a real error by making sure the value in R0 ++ is a real error number. Linus said he will make sure the no syscall ++ returns a value in -1 .. -4095 as a valid result so we can safely ++ test with -4095. */ ++ ++# undef PSEUDO ++# define PSEUDO(name, syscall_name, args) \ ++ .text; \ ++ ENTRY (name); \ ++ DO_CALL (syscall_name, args); \ ++ cmn x0, #4095; \ ++ b.cs .Lsyscall_error; ++ ++# undef PSEUDO_END ++# define PSEUDO_END(name) \ ++ SYSCALL_ERROR_HANDLER \ ++ END (name) ++ ++# undef PSEUDO_NOERRNO ++# define PSEUDO_NOERRNO(name, syscall_name, args) \ ++ .text; \ ++ ENTRY (name); \ ++ DO_CALL (syscall_name, args); ++ ++# undef PSEUDO_END_NOERRNO ++# define PSEUDO_END_NOERRNO(name) \ ++ END (name) ++ ++# define ret_NOERRNO ret ++ ++/* The function has to return the error code. */ ++# undef PSEUDO_ERRVAL ++# define PSEUDO_ERRVAL(name, syscall_name, args) \ ++ .text; \ ++ ENTRY (name) \ ++ DO_CALL (syscall_name, args); \ ++ neg x0, x0 ++ ++# undef PSEUDO_END_ERRVAL ++# define PSEUDO_END_ERRVAL(name) \ ++ END (name) ++ ++# define ret_ERRVAL ret ++ ++# if !IS_IN (libc) ++# define SYSCALL_ERROR .Lsyscall_error ++# if RTLD_PRIVATE_ERRNO ++# define SYSCALL_ERROR_HANDLER \ ++.Lsyscall_error: \ ++ adrp x1, C_SYMBOL_NAME(rtld_errno); \ ++ neg w0, w0; \ ++ str w0, [x1, :lo12:C_SYMBOL_NAME(rtld_errno)]; \ ++ mov x0, -1; \ ++ RET; ++# else ++ ++# define SYSCALL_ERROR_HANDLER \ ++.Lsyscall_error: \ ++ adrp x1, :gottprel:errno; \ ++ neg w2, w0; \ ++ ldr PTR_REG(1), [x1, :gottprel_lo12:errno]; \ ++ mrs x3, tpidr_el0; \ ++ mov x0, -1; \ ++ str w2, [x1, x3]; \ ++ RET; ++# endif ++# else ++# define SYSCALL_ERROR __syscall_error ++# define SYSCALL_ERROR_HANDLER \ ++.Lsyscall_error: \ ++ b __syscall_error; ++# endif ++ ++/* Linux takes system call args in registers: ++ syscall number x8 ++ arg 1 x0 ++ arg 2 x1 ++ arg 3 x2 ++ arg 4 x3 ++ arg 5 x4 ++ arg 6 x5 ++ arg 7 x6 ++ ++ The compiler is going to form a call by coming here, through PSEUDO, with ++ arguments ++ syscall number in the DO_CALL macro ++ arg 1 x0 ++ arg 2 x1 ++ arg 3 x2 ++ arg 4 x3 ++ arg 5 x4 ++ arg 6 x5 ++ arg 7 x6 ++ ++*/ ++ ++# undef DO_CALL ++# define DO_CALL(syscall_name, args) \ ++ mov x8, SYS_ify (syscall_name); \ ++ svc 0 ++ ++#else /* not __ASSEMBLER__ */ ++ ++ ++/* List of system calls which are supported as vsyscalls. */ ++# define HAVE_CLOCK_GETRES_VSYSCALL 1 ++# define HAVE_CLOCK_GETTIME_VSYSCALL 1 ++# define HAVE_GETTIMEOFDAY_VSYSCALL 1 ++ ++/* Previously AArch64 used the generic version without the libc_hidden_def ++ which lead in a non existent __send symbol in libc.so. */ ++# undef HAVE_INTERNAL_SEND_SYMBOL ++ ++# define SINGLE_THREAD_BY_GLOBAL 1 ++ ++/* Define a macro which expands into the inline wrapper code for a system ++ call. */ ++# undef INLINE_SYSCALL ++# define INLINE_SYSCALL(name, nr, args...) \ ++ ({ unsigned long _sys_result = INTERNAL_SYSCALL (name, , nr, args); \ ++ if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_sys_result, ), 0))\ ++ { \ ++ __set_errno (INTERNAL_SYSCALL_ERRNO (_sys_result, )); \ ++ _sys_result = (unsigned long) -1; \ ++ } \ ++ (long) _sys_result; }) ++ ++# undef INTERNAL_SYSCALL_DECL ++# define INTERNAL_SYSCALL_DECL(err) do { } while (0) ++ ++# undef INTERNAL_SYSCALL_RAW ++# define INTERNAL_SYSCALL_RAW(name, err, nr, args...) \ ++ ({ long _sys_result; \ ++ { \ ++ LOAD_ARGS_##nr (args) \ ++ register long _x8 asm ("x8") = (name); \ ++ asm volatile ("svc 0 // syscall " # name \ ++ : "=r" (_x0) : "r"(_x8) ASM_ARGS_##nr : "memory"); \ ++ _sys_result = _x0; \ ++ } \ ++ _sys_result; }) ++ ++# undef INTERNAL_SYSCALL ++# define INTERNAL_SYSCALL(name, err, nr, args...) \ ++ INTERNAL_SYSCALL_RAW(SYS_ify(name), err, nr, args) ++ ++# undef INTERNAL_SYSCALL_AARCH64 ++# define INTERNAL_SYSCALL_AARCH64(name, err, nr, args...) \ ++ INTERNAL_SYSCALL_RAW(__ARM_NR_##name, err, nr, args) ++ ++# undef INTERNAL_SYSCALL_ERROR_P ++# define INTERNAL_SYSCALL_ERROR_P(val, err) \ ++ ((unsigned long) (val) >= (unsigned long) -4095) ++ ++# undef INTERNAL_SYSCALL_ERRNO ++# define INTERNAL_SYSCALL_ERRNO(val, err) (-(val)) ++ ++# define LOAD_ARGS_0() \ ++ register long _x0 asm ("x0"); ++# define LOAD_ARGS_1(x0) \ ++ long _x0tmp = (long) (x0); \ ++ LOAD_ARGS_0 () \ ++ _x0 = _x0tmp; ++# define LOAD_ARGS_2(x0, x1) \ ++ long _x1tmp = (long) (x1); \ ++ LOAD_ARGS_1 (x0) \ ++ register long _x1 asm ("x1") = _x1tmp; ++# define LOAD_ARGS_3(x0, x1, x2) \ ++ long _x2tmp = (long) (x2); \ ++ LOAD_ARGS_2 (x0, x1) \ ++ register long _x2 asm ("x2") = _x2tmp; ++# define LOAD_ARGS_4(x0, x1, x2, x3) \ ++ long _x3tmp = (long) (x3); \ ++ LOAD_ARGS_3 (x0, x1, x2) \ ++ register long _x3 asm ("x3") = _x3tmp; ++# define LOAD_ARGS_5(x0, x1, x2, x3, x4) \ ++ long _x4tmp = (long) (x4); \ ++ LOAD_ARGS_4 (x0, x1, x2, x3) \ ++ register long _x4 asm ("x4") = _x4tmp; ++# define LOAD_ARGS_6(x0, x1, x2, x3, x4, x5) \ ++ long _x5tmp = (long) (x5); \ ++ LOAD_ARGS_5 (x0, x1, x2, x3, x4) \ ++ register long _x5 asm ("x5") = _x5tmp; ++# define LOAD_ARGS_7(x0, x1, x2, x3, x4, x5, x6)\ ++ long _x6tmp = (long) (x6); \ ++ LOAD_ARGS_6 (x0, x1, x2, x3, x4, x5) \ ++ register long _x6 asm ("x6") = _x6tmp; ++ ++# define ASM_ARGS_0 ++# define ASM_ARGS_1 , "r" (_x0) ++# define ASM_ARGS_2 ASM_ARGS_1, "r" (_x1) ++# define ASM_ARGS_3 ASM_ARGS_2, "r" (_x2) ++# define ASM_ARGS_4 ASM_ARGS_3, "r" (_x3) ++# define ASM_ARGS_5 ASM_ARGS_4, "r" (_x4) ++# define ASM_ARGS_6 ASM_ARGS_5, "r" (_x5) ++# define ASM_ARGS_7 ASM_ARGS_6, "r" (_x6) ++ ++# undef INTERNAL_SYSCALL_NCS ++# define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \ ++ INTERNAL_SYSCALL_RAW (number, err, nr, args) ++ ++#endif /* __ASSEMBLER__ */ ++ ++/* Pointer mangling is supported for AArch64. */ ++#if (IS_IN (rtld) || \ ++ (!defined SHARED && (IS_IN (libc) \ ++ || IS_IN (libpthread)))) ++# ifdef __ASSEMBLER__ ++/* Note, dst, src, guard, and tmp are all register numbers rather than ++ register names so they will work with both ILP32 and LP64. */ ++# define PTR_MANGLE(dst, src, guard, tmp) \ ++ LDST_PCREL (ldr, guard, tmp, C_SYMBOL_NAME(__pointer_chk_guard_local)); \ ++ PTR_MANGLE2 (dst, src, guard) ++/* Use PTR_MANGLE2 for efficiency if guard is already loaded. */ ++# define PTR_MANGLE2(dst, src, guard)\ ++ eor x##dst, x##src, x##guard ++# define PTR_DEMANGLE(dst, src, guard, tmp)\ ++ PTR_MANGLE (dst, src, guard, tmp) ++# define PTR_DEMANGLE2(dst, src, guard)\ ++ PTR_MANGLE2 (dst, src, guard) ++# else ++extern uintptr_t __pointer_chk_guard_local attribute_relro attribute_hidden; ++# define PTR_MANGLE(var) \ ++ (var) = (__typeof (var)) ((uintptr_t) (var) ^ __pointer_chk_guard_local) ++# define PTR_DEMANGLE(var) PTR_MANGLE (var) ++# endif ++#else ++# ifdef __ASSEMBLER__ ++/* Note, dst, src, guard, and tmp are all register numbers rather than ++ register names so they will work with both ILP32 and LP64. */ ++# define PTR_MANGLE(dst, src, guard, tmp) \ ++ LDST_GLOBAL (ldr, guard, tmp, C_SYMBOL_NAME(__pointer_chk_guard)); \ ++ PTR_MANGLE2 (dst, src, guard) ++/* Use PTR_MANGLE2 for efficiency if guard is already loaded. */ ++# define PTR_MANGLE2(dst, src, guard)\ ++ eor x##dst, x##src, x##guard ++# define PTR_DEMANGLE(dst, src, guard, tmp)\ ++ PTR_MANGLE (dst, src, guard, tmp) ++# define PTR_DEMANGLE2(dst, src, guard)\ ++ PTR_MANGLE2 (dst, src, guard) ++# else ++extern uintptr_t __pointer_chk_guard attribute_relro; ++# define PTR_MANGLE(var) \ ++ (var) = (__typeof (var)) ((uintptr_t) (var) ^ __pointer_chk_guard) ++# define PTR_DEMANGLE(var) PTR_MANGLE (var) ++# endif ++#endif ++ ++#endif /* linux/aarch64/sysdep.h */ +diff --git a/nptl_2_17/sysdeps/unix/sysv/linux/generic/sysdep_2_17.h b/nptl_2_17/sysdeps/unix/sysv/linux/generic/sysdep_2_17.h +new file mode 100644 +index 00000000..1898464d +--- /dev/null ++++ b/nptl_2_17/sysdeps/unix/sysv/linux/generic/sysdep_2_17.h +@@ -0,0 +1,35 @@ ++/* Copyright (C) 2011-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Chris Metcalf , 2011. ++ ++ 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 ++ ++/* Provide the common name to allow more code reuse. */ ++#ifdef __NR_llseek ++# define __NR__llseek __NR_llseek ++#endif ++ ++#if __WORDSIZE == 64 ++/* By defining the older names, glibc will build syscall wrappers for ++ both pread and pread64; sysdeps/unix/sysv/linux/wordsize-64/pread64.c ++ will suppress generating any separate code for pread64.c. */ ++#define __NR_pread __NR_pread64 ++#define __NR_pwrite __NR_pwrite64 ++#endif +diff --git a/nptl_2_17/sysdeps/unix/sysv/linux/internal-signals_2_17.h b/nptl_2_17/sysdeps/unix/sysv/linux/internal-signals_2_17.h +new file mode 100644 +index 00000000..8f2b45c3 +--- /dev/null ++++ b/nptl_2_17/sysdeps/unix/sysv/linux/internal-signals_2_17.h +@@ -0,0 +1,91 @@ ++/* Special use of signals internally. Linux version. ++ Copyright (C) 2014-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 __INTERNAL_SIGNALS_H ++# define __INTERNAL_SIGNALS_H ++ ++#include ++#include ++#include ++#include ++ ++/* The signal used for asynchronous cancelation. */ ++#define SIGCANCEL __SIGRTMIN ++ ++ ++/* Signal needed for the kernel-supported POSIX timer implementation. ++ We can reuse the cancellation signal since we can distinguish ++ cancellation from timer expirations. */ ++#define SIGTIMER SIGCANCEL ++ ++ ++/* Signal used to implement the setuid et.al. functions. */ ++#define SIGSETXID (__SIGRTMIN + 1) ++ ++ ++/* Return is sig is used internally. */ ++static inline bool ++__is_internal_signal (int sig) ++{ ++ return (sig == SIGCANCEL) || (sig == SIGSETXID); ++} ++ ++/* Remove internal glibc signal from the mask. */ ++static inline void ++__clear_internal_signals (sigset_t *set) ++{ ++ __sigdelset (set, SIGCANCEL); ++ __sigdelset (set, SIGSETXID); ++} ++ ++#define SIGALL_SET \ ++ ((__sigset_t) { .__val = {[0 ... _SIGSET_NWORDS-1 ] = -1 } }) ++ ++/* Block all signals, including internal glibc ones. */ ++static inline int ++__libc_signal_block_all (sigset_t *set) ++{ ++ INTERNAL_SYSCALL_DECL (err); ++ return INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_BLOCK, &SIGALL_SET, ++ set, _NSIG / 8); ++} ++ ++/* Block all application signals (excluding internal glibc ones). */ ++static inline int ++__libc_signal_block_app (sigset_t *set) ++{ ++ sigset_t allset = SIGALL_SET; ++ __clear_internal_signals (&allset); ++ INTERNAL_SYSCALL_DECL (err); ++ return INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_BLOCK, &allset, set, ++ _NSIG / 8); ++} ++ ++/* Restore current process signal mask. */ ++static inline int ++__libc_signal_restore_set (const sigset_t *set) ++{ ++ INTERNAL_SYSCALL_DECL (err); ++ return INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, set, NULL, ++ _NSIG / 8); ++} ++ ++/* Used to communicate with signal handler. */ ++extern struct xid_command *__xidcmd attribute_hidden; ++ ++#endif +diff --git a/nptl_2_17/sysdeps/unix/sysv/linux/lowlevellock-futex_2_17.h b/nptl_2_17/sysdeps/unix/sysv/linux/lowlevellock-futex_2_17.h +new file mode 100644 +index 00000000..399de2e5 +--- /dev/null ++++ b/nptl_2_17/sysdeps/unix/sysv/linux/lowlevellock-futex_2_17.h +@@ -0,0 +1,150 @@ ++/* Low-level locking access to futex facilities. Linux version. ++ Copyright (C) 2005-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 _LOWLEVELLOCK_FUTEX_H ++#define _LOWLEVELLOCK_FUTEX_H 1 ++ ++#ifndef __ASSEMBLER__ ++#include ++#include ++#include ++#endif ++ ++#define FUTEX_WAIT 0 ++#define FUTEX_WAKE 1 ++#define FUTEX_REQUEUE 3 ++#define FUTEX_CMP_REQUEUE 4 ++#define FUTEX_WAKE_OP 5 ++#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE ((4 << 24) | 1) ++#define FUTEX_LOCK_PI 6 ++#define FUTEX_UNLOCK_PI 7 ++#define FUTEX_TRYLOCK_PI 8 ++#define FUTEX_WAIT_BITSET 9 ++#define FUTEX_WAKE_BITSET 10 ++#define FUTEX_WAIT_REQUEUE_PI 11 ++#define FUTEX_CMP_REQUEUE_PI 12 ++#define FUTEX_PRIVATE_FLAG 128 ++#define FUTEX_CLOCK_REALTIME 256 ++ ++#define FUTEX_BITSET_MATCH_ANY 0xffffffff ++ ++/* Values for 'private' parameter of locking macros. Yes, the ++ definition seems to be backwards. But it is not. The bit will be ++ reversed before passing to the system call. */ ++#define LLL_PRIVATE 0 ++#define LLL_SHARED FUTEX_PRIVATE_FLAG ++ ++#ifndef __ASSEMBLER__ ++ ++#if IS_IN (libc) || IS_IN (rtld) ++/* In libc.so or ld.so all futexes are private. */ ++# define __lll_private_flag(fl, private) \ ++ ({ \ ++ /* Prevent warnings in callers of this macro. */ \ ++ int __lll_private_flag_priv __attribute__ ((unused)); \ ++ __lll_private_flag_priv = (private); \ ++ ((fl) | FUTEX_PRIVATE_FLAG); \ ++ }) ++#else ++# define __lll_private_flag(fl, private) \ ++ (((fl) | FUTEX_PRIVATE_FLAG) ^ (private)) ++#endif ++ ++#define lll_futex_syscall(nargs, futexp, op, ...) \ ++ ({ \ ++ INTERNAL_SYSCALL_DECL (__err); \ ++ long int __ret = INTERNAL_SYSCALL (futex, __err, nargs, futexp, op, \ ++ __VA_ARGS__); \ ++ (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (__ret, __err)) \ ++ ? -INTERNAL_SYSCALL_ERRNO (__ret, __err) : 0); \ ++ }) ++ ++#define lll_futex_wait(futexp, val, private) \ ++ lll_futex_timed_wait (futexp, val, NULL, private) ++ ++#define lll_futex_timed_wait(futexp, val, timeout, private) \ ++ lll_futex_syscall (4, futexp, \ ++ __lll_private_flag (FUTEX_WAIT, private), \ ++ val, timeout) ++ ++/* 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; \ ++ }) ++ ++#define lll_futex_wake(futexp, nr, private) \ ++ lll_futex_syscall (4, futexp, \ ++ __lll_private_flag (FUTEX_WAKE, private), nr, 0) ++ ++/* Returns non-zero if error happened, zero if success. */ ++#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val, private) \ ++ lll_futex_syscall (6, futexp, \ ++ __lll_private_flag (FUTEX_CMP_REQUEUE, private), \ ++ nr_wake, nr_move, mutex, val) ++ ++/* Returns non-zero if error happened, zero if success. */ ++#define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \ ++ lll_futex_syscall (6, futexp, \ ++ __lll_private_flag (FUTEX_WAKE_OP, private), \ ++ nr_wake, nr_wake2, futexp2, \ ++ FUTEX_OP_CLEAR_WAKE_IF_GT_ONE) ++ ++/* Priority Inheritance support. */ ++#define lll_futex_wait_requeue_pi(futexp, val, mutex, private) \ ++ lll_futex_timed_wait_requeue_pi (futexp, val, NULL, 0, mutex, private) ++ ++#define lll_futex_timed_wait_requeue_pi(futexp, val, timeout, clockbit, \ ++ mutex, private) \ ++ lll_futex_syscall (5, futexp, \ ++ __lll_private_flag (FUTEX_WAIT_REQUEUE_PI \ ++ | (clockbit), private), \ ++ val, timeout, mutex) ++ ++ ++#define lll_futex_cmp_requeue_pi(futexp, nr_wake, nr_move, mutex, \ ++ val, private) \ ++ lll_futex_syscall (6, futexp, \ ++ __lll_private_flag (FUTEX_CMP_REQUEUE_PI, \ ++ private), \ ++ nr_wake, nr_move, mutex, val) ++ ++#endif /* !__ASSEMBLER__ */ ++ ++#endif /* lowlevellock-futex.h */ +diff --git a/nptl_2_17/sysdeps/unix/sysv/linux/not-cancel_2_17.h b/nptl_2_17/sysdeps/unix/sysv/linux/not-cancel_2_17.h +new file mode 100644 +index 00000000..602307db +--- /dev/null ++++ b/nptl_2_17/sysdeps/unix/sysv/linux/not-cancel_2_17.h +@@ -0,0 +1,93 @@ ++/* Uncancelable versions of cancelable interfaces. Linux/NPTL version. ++ 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 NOT_CANCEL_H ++# define NOT_CANCEL_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Non cancellable open syscall. */ ++__typeof (open) __open_nocancel; ++ ++/* Non cancellable open syscall (LFS version). */ ++__typeof (open64) __open64_nocancel; ++ ++/* Non cancellable openat syscall. */ ++__typeof (openat) __openat_nocancel; ++ ++/* Non cacellable openat syscall (LFS version). */ ++__typeof (openat64) __openat64_nocancel; ++ ++/* Non cancellable read syscall. */ ++__typeof (__read) __read_nocancel; ++ ++/* Uncancelable write. */ ++__typeof (__write) __write_nocancel; ++ ++/* Uncancelable close. */ ++__typeof (__close) __close_nocancel; ++ ++/* Non cancellable close syscall that does not also set errno in case of ++ failure. */ ++static inline void ++__close_nocancel_nostatus (int fd) ++{ ++ __close_nocancel (fd); ++} ++ ++/* Non cancellable writev syscall that does not also set errno in case of ++ failure. */ ++static inline void ++__writev_nocancel_nostatus (int fd, const struct iovec *iov, int iovcnt) ++{ ++ INTERNAL_SYSCALL_DECL (err); ++ INTERNAL_SYSCALL_CALL (writev, err, fd, iov, iovcnt); ++} ++ ++/* Uncancelable waitpid. */ ++__typeof (waitpid) __waitpid_nocancel; ++ ++/* Uncancelable pause. */ ++__typeof (pause) __pause_nocancel; ++ ++/* Uncancelable nanosleep. */ ++__typeof (__nanosleep) __nanosleep_nocancel; ++ ++/* Uncancelable fcntl. */ ++__typeof (__fcntl) __fcntl64_nocancel; ++ ++hidden_proto (__open_nocancel) ++hidden_proto (__open64_nocancel) ++hidden_proto (__openat_nocancel) ++hidden_proto (__openat64_nocancel) ++hidden_proto (__read_nocancel) ++hidden_proto (__write_nocancel) ++hidden_proto (__close_nocancel) ++hidden_proto (__waitpid_nocancel) ++hidden_proto (__pause_nocancel) ++hidden_proto (__nanosleep_nocancel) ++hidden_proto (__fcntl64_nocancel) ++ ++#endif /* NOT_CANCEL_H */ +diff --git a/nptl_2_17/sysdeps/unix/sysv/linux/sysdep_2_17.h b/nptl_2_17/sysdeps/unix/sysv/linux/sysdep_2_17.h +new file mode 100644 +index 00000000..4fd0a9ba +--- /dev/null ++++ b/nptl_2_17/sysdeps/unix/sysv/linux/sysdep_2_17.h +@@ -0,0 +1,68 @@ ++/* Copyright (C) 2015-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 ++ ++/* Set error number and return -1. A target may choose to return the ++ internal function, __syscall_error, which sets errno and returns -1. ++ We use -1l, instead of -1, so that it can be casted to (void *). */ ++#define INLINE_SYSCALL_ERROR_RETURN_VALUE(err) \ ++ ({ \ ++ __set_errno (err); \ ++ -1l; \ ++ }) ++ ++/* Provide a dummy argument that can be used to force register ++ alignment for register pairs if required by the syscall ABI. */ ++#ifdef __ASSUME_ALIGNED_REGISTER_PAIRS ++#define __ALIGNMENT_ARG 0, ++#define __ALIGNMENT_COUNT(a,b) b ++#else ++#define __ALIGNMENT_ARG ++#define __ALIGNMENT_COUNT(a,b) a ++#endif ++ ++/* Provide a common macro to pass 64-bit value on syscalls. */ ++#if __WORDSIZE == 64 || defined __ASSUME_WORDSIZE64_ILP32 ++# define SYSCALL_LL(val) (val) ++# define SYSCALL_LL64(val) (val) ++#else ++#define SYSCALL_LL(val) \ ++ __LONG_LONG_PAIR ((val) >> 31, (val)) ++#define SYSCALL_LL64(val) \ ++ __LONG_LONG_PAIR ((long) ((val) >> 32), (long) ((val) & 0xffffffff)) ++#endif ++ ++/* Provide a common macro to pass 64-bit value on pread and pwrite ++ syscalls. */ ++#ifdef __ASSUME_PRW_DUMMY_ARG ++# define SYSCALL_LL_PRW(val) 0, SYSCALL_LL (val) ++# define SYSCALL_LL64_PRW(val) 0, SYSCALL_LL64 (val) ++#else ++# define SYSCALL_LL_PRW(val) __ALIGNMENT_ARG SYSCALL_LL (val) ++# define SYSCALL_LL64_PRW(val) __ALIGNMENT_ARG SYSCALL_LL64 (val) ++#endif ++ ++/* Provide a macro to pass the off{64}_t argument on p{readv,writev}{64}. */ ++#define LO_HI_LONG(val) \ ++ (long) (val), \ ++ (long) (((uint64_t) (val)) >> 32) ++ ++/* Exports the __send symbol on send.c linux implementation (some ABI have ++ it missing due the usage of a old generic version without it). */ ++#define HAVE_INTERNAL_SEND_SYMBOL 1 +diff --git a/nptl_2_17/sysdeps/unix/sysv/linux/x86_64/sysdep_2_17.h b/nptl_2_17/sysdeps/unix/sysv/linux/x86_64/sysdep_2_17.h +new file mode 100644 +index 00000000..8cf61c21 +--- /dev/null ++++ b/nptl_2_17/sysdeps/unix/sysv/linux/x86_64/sysdep_2_17.h +@@ -0,0 +1,432 @@ ++/* Copyright (C) 2001-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 _LINUX_X86_64_SYSDEP_H ++#define _LINUX_X86_64_SYSDEP_H 1 ++ ++/* There is some commonality. */ ++#include ++#include ++#include "descr_2_17.h" ++#include ++ ++/* Defines RTLD_PRIVATE_ERRNO. */ ++#include ++ ++/* For Linux we can use the system call table in the header file ++ /usr/include/asm/unistd.h ++ of the kernel. But these symbols do not follow the SYS_* syntax ++ so we have to redefine the `SYS_ify' macro here. */ ++#undef SYS_ify ++#define SYS_ify(syscall_name) __NR_##syscall_name ++ ++/* This is a kludge to make syscalls.list find these under the names ++ pread and pwrite, since some kernel headers define those names ++ and some define the *64 names for the same system calls. */ ++#if !defined __NR_pread && defined __NR_pread64 ++# define __NR_pread __NR_pread64 ++#endif ++#if !defined __NR_pwrite && defined __NR_pwrite64 ++# define __NR_pwrite __NR_pwrite64 ++#endif ++ ++/* This is to help the old kernel headers where __NR_semtimedop is not ++ available. */ ++#ifndef __NR_semtimedop ++# define __NR_semtimedop 220 ++#endif ++ ++ ++#ifdef __ASSEMBLER__ ++ ++/* Linux uses a negative return value to indicate syscall errors, ++ unlike most Unices, which use the condition codes' carry flag. ++ ++ Since version 2.1 the return value of a system call might be ++ negative even if the call succeeded. E.g., the `lseek' system call ++ might return a large offset. Therefore we must not anymore test ++ for < 0, but test for a real error by making sure the value in %eax ++ is a real error number. Linus said he will make sure the no syscall ++ returns a value in -1 .. -4095 as a valid result so we can savely ++ test with -4095. */ ++ ++/* We don't want the label for the error handle to be global when we define ++ it here. */ ++# ifdef PIC ++# define SYSCALL_ERROR_LABEL 0f ++# else ++# define SYSCALL_ERROR_LABEL syscall_error ++# endif ++ ++# undef PSEUDO ++# define PSEUDO(name, syscall_name, args) \ ++ .text; \ ++ ENTRY (name) \ ++ DO_CALL (syscall_name, args); \ ++ cmpq $-4095, %rax; \ ++ jae SYSCALL_ERROR_LABEL ++ ++# undef PSEUDO_END ++# define PSEUDO_END(name) \ ++ SYSCALL_ERROR_HANDLER \ ++ END (name) ++ ++# undef PSEUDO_NOERRNO ++# define PSEUDO_NOERRNO(name, syscall_name, args) \ ++ .text; \ ++ ENTRY (name) \ ++ DO_CALL (syscall_name, args) ++ ++# undef PSEUDO_END_NOERRNO ++# define PSEUDO_END_NOERRNO(name) \ ++ END (name) ++ ++# define ret_NOERRNO ret ++ ++# undef PSEUDO_ERRVAL ++# define PSEUDO_ERRVAL(name, syscall_name, args) \ ++ .text; \ ++ ENTRY (name) \ ++ DO_CALL (syscall_name, args); \ ++ negq %rax ++ ++# undef PSEUDO_END_ERRVAL ++# define PSEUDO_END_ERRVAL(name) \ ++ END (name) ++ ++# define ret_ERRVAL ret ++ ++# if defined PIC && RTLD_PRIVATE_ERRNO ++# define SYSCALL_SET_ERRNO \ ++ lea rtld_errno(%rip), %RCX_LP; \ ++ neg %eax; \ ++ movl %eax, (%rcx) ++# else ++# if IS_IN (libc) ++# define SYSCALL_ERROR_ERRNO __libc_errno ++# else ++# define SYSCALL_ERROR_ERRNO errno ++# endif ++# define SYSCALL_SET_ERRNO \ ++ movq SYSCALL_ERROR_ERRNO@GOTTPOFF(%rip), %rcx;\ ++ neg %eax; \ ++ movl %eax, %fs:(%rcx); ++# endif ++ ++# ifndef PIC ++# define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */ ++# else ++# define SYSCALL_ERROR_HANDLER \ ++0: \ ++ SYSCALL_SET_ERRNO; \ ++ or $-1, %RAX_LP; \ ++ ret; ++# endif /* PIC */ ++ ++/* The Linux/x86-64 kernel expects the system call parameters in ++ registers according to the following table: ++ ++ syscall number rax ++ arg 1 rdi ++ arg 2 rsi ++ arg 3 rdx ++ arg 4 r10 ++ arg 5 r8 ++ arg 6 r9 ++ ++ The Linux kernel uses and destroys internally these registers: ++ return address from ++ syscall rcx ++ eflags from syscall r11 ++ ++ Normal function call, including calls to the system call stub ++ functions in the libc, get the first six parameters passed in ++ registers and the seventh parameter and later on the stack. The ++ register use is as follows: ++ ++ system call number in the DO_CALL macro ++ arg 1 rdi ++ arg 2 rsi ++ arg 3 rdx ++ arg 4 rcx ++ arg 5 r8 ++ arg 6 r9 ++ ++ We have to take care that the stack is aligned to 16 bytes. When ++ called the stack is not aligned since the return address has just ++ been pushed. ++ ++ ++ Syscalls of more than 6 arguments are not supported. */ ++ ++# undef DO_CALL ++# define DO_CALL(syscall_name, args) \ ++ DOARGS_##args \ ++ movl $SYS_ify (syscall_name), %eax; \ ++ syscall; ++ ++# define DOARGS_0 /* nothing */ ++# define DOARGS_1 /* nothing */ ++# define DOARGS_2 /* nothing */ ++# define DOARGS_3 /* nothing */ ++# define DOARGS_4 movq %rcx, %r10; ++# define DOARGS_5 DOARGS_4 ++# define DOARGS_6 DOARGS_5 ++ ++#else /* !__ASSEMBLER__ */ ++/* Define a macro which expands inline into the wrapper code for a system ++ call. */ ++# undef INLINE_SYSCALL ++# define INLINE_SYSCALL(name, nr, args...) \ ++ ({ \ ++ unsigned long int resultvar = INTERNAL_SYSCALL (name, , nr, args); \ ++ if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (resultvar, ))) \ ++ { \ ++ __set_errno (INTERNAL_SYSCALL_ERRNO (resultvar, )); \ ++ resultvar = (unsigned long int) -1; \ ++ } \ ++ (long int) resultvar; }) ++ ++/* Define a macro with explicit types for arguments, which expands inline ++ into the wrapper code for a system call. It should be used when size ++ of any argument > size of long int. */ ++# undef INLINE_SYSCALL_TYPES ++# define INLINE_SYSCALL_TYPES(name, nr, args...) \ ++ ({ \ ++ unsigned long int resultvar = INTERNAL_SYSCALL_TYPES (name, , nr, args); \ ++ if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (resultvar, ))) \ ++ { \ ++ __set_errno (INTERNAL_SYSCALL_ERRNO (resultvar, )); \ ++ resultvar = (unsigned long int) -1; \ ++ } \ ++ (long int) resultvar; }) ++ ++# undef INTERNAL_SYSCALL_DECL ++# define INTERNAL_SYSCALL_DECL(err) do { } while (0) ++ ++/* Registers clobbered by syscall. */ ++# define REGISTERS_CLOBBERED_BY_SYSCALL "cc", "r11", "cx" ++ ++/* Create a variable 'name' based on type 'X' to avoid explicit types. ++ This is mainly used set use 64-bits arguments in x32. */ ++#define TYPEFY(X, name) __typeof__ ((X) - (X)) name ++/* Explicit cast the argument to avoid integer from pointer warning on ++ x32. */ ++#define ARGIFY(X) ((__typeof__ ((X) - (X))) (X)) ++ ++#undef INTERNAL_SYSCALL ++#define INTERNAL_SYSCALL(name, err, nr, args...) \ ++ internal_syscall##nr (SYS_ify (name), err, args) ++ ++#undef INTERNAL_SYSCALL_NCS ++#define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \ ++ internal_syscall##nr (number, err, args) ++ ++#undef internal_syscall0 ++#define internal_syscall0(number, err, dummy...) \ ++({ \ ++ unsigned long int resultvar; \ ++ asm volatile ( \ ++ "syscall\n\t" \ ++ : "=a" (resultvar) \ ++ : "0" (number) \ ++ : "memory", REGISTERS_CLOBBERED_BY_SYSCALL); \ ++ (long int) resultvar; \ ++}) ++ ++#undef internal_syscall1 ++#define internal_syscall1(number, err, arg1) \ ++({ \ ++ unsigned long int resultvar; \ ++ TYPEFY (arg1, __arg1) = ARGIFY (arg1); \ ++ register TYPEFY (arg1, _a1) asm ("rdi") = __arg1; \ ++ asm volatile ( \ ++ "syscall\n\t" \ ++ : "=a" (resultvar) \ ++ : "0" (number), "r" (_a1) \ ++ : "memory", REGISTERS_CLOBBERED_BY_SYSCALL); \ ++ (long int) resultvar; \ ++}) ++ ++#undef internal_syscall2 ++#define internal_syscall2(number, err, arg1, arg2) \ ++({ \ ++ unsigned long int resultvar; \ ++ TYPEFY (arg2, __arg2) = ARGIFY (arg2); \ ++ TYPEFY (arg1, __arg1) = ARGIFY (arg1); \ ++ register TYPEFY (arg2, _a2) asm ("rsi") = __arg2; \ ++ register TYPEFY (arg1, _a1) asm ("rdi") = __arg1; \ ++ asm volatile ( \ ++ "syscall\n\t" \ ++ : "=a" (resultvar) \ ++ : "0" (number), "r" (_a1), "r" (_a2) \ ++ : "memory", REGISTERS_CLOBBERED_BY_SYSCALL); \ ++ (long int) resultvar; \ ++}) ++ ++#undef internal_syscall3 ++#define internal_syscall3(number, err, arg1, arg2, arg3) \ ++({ \ ++ unsigned long int resultvar; \ ++ TYPEFY (arg3, __arg3) = ARGIFY (arg3); \ ++ TYPEFY (arg2, __arg2) = ARGIFY (arg2); \ ++ TYPEFY (arg1, __arg1) = ARGIFY (arg1); \ ++ register TYPEFY (arg3, _a3) asm ("rdx") = __arg3; \ ++ register TYPEFY (arg2, _a2) asm ("rsi") = __arg2; \ ++ register TYPEFY (arg1, _a1) asm ("rdi") = __arg1; \ ++ asm volatile ( \ ++ "syscall\n\t" \ ++ : "=a" (resultvar) \ ++ : "0" (number), "r" (_a1), "r" (_a2), "r" (_a3) \ ++ : "memory", REGISTERS_CLOBBERED_BY_SYSCALL); \ ++ (long int) resultvar; \ ++}) ++ ++#undef internal_syscall4 ++#define internal_syscall4(number, err, arg1, arg2, arg3, arg4) \ ++({ \ ++ unsigned long int resultvar; \ ++ TYPEFY (arg4, __arg4) = ARGIFY (arg4); \ ++ TYPEFY (arg3, __arg3) = ARGIFY (arg3); \ ++ TYPEFY (arg2, __arg2) = ARGIFY (arg2); \ ++ TYPEFY (arg1, __arg1) = ARGIFY (arg1); \ ++ register TYPEFY (arg4, _a4) asm ("r10") = __arg4; \ ++ register TYPEFY (arg3, _a3) asm ("rdx") = __arg3; \ ++ register TYPEFY (arg2, _a2) asm ("rsi") = __arg2; \ ++ register TYPEFY (arg1, _a1) asm ("rdi") = __arg1; \ ++ asm volatile ( \ ++ "syscall\n\t" \ ++ : "=a" (resultvar) \ ++ : "0" (number), "r" (_a1), "r" (_a2), "r" (_a3), "r" (_a4) \ ++ : "memory", REGISTERS_CLOBBERED_BY_SYSCALL); \ ++ (long int) resultvar; \ ++}) ++ ++#undef internal_syscall5 ++#define internal_syscall5(number, err, arg1, arg2, arg3, arg4, arg5) \ ++({ \ ++ unsigned long int resultvar; \ ++ TYPEFY (arg5, __arg5) = ARGIFY (arg5); \ ++ TYPEFY (arg4, __arg4) = ARGIFY (arg4); \ ++ TYPEFY (arg3, __arg3) = ARGIFY (arg3); \ ++ TYPEFY (arg2, __arg2) = ARGIFY (arg2); \ ++ TYPEFY (arg1, __arg1) = ARGIFY (arg1); \ ++ register TYPEFY (arg5, _a5) asm ("r8") = __arg5; \ ++ register TYPEFY (arg4, _a4) asm ("r10") = __arg4; \ ++ register TYPEFY (arg3, _a3) asm ("rdx") = __arg3; \ ++ register TYPEFY (arg2, _a2) asm ("rsi") = __arg2; \ ++ register TYPEFY (arg1, _a1) asm ("rdi") = __arg1; \ ++ asm volatile ( \ ++ "syscall\n\t" \ ++ : "=a" (resultvar) \ ++ : "0" (number), "r" (_a1), "r" (_a2), "r" (_a3), "r" (_a4), \ ++ "r" (_a5) \ ++ : "memory", REGISTERS_CLOBBERED_BY_SYSCALL); \ ++ (long int) resultvar; \ ++}) ++ ++#undef internal_syscall6 ++#define internal_syscall6(number, err, arg1, arg2, arg3, arg4, arg5, arg6) \ ++({ \ ++ unsigned long int resultvar; \ ++ TYPEFY (arg6, __arg6) = ARGIFY (arg6); \ ++ TYPEFY (arg5, __arg5) = ARGIFY (arg5); \ ++ TYPEFY (arg4, __arg4) = ARGIFY (arg4); \ ++ TYPEFY (arg3, __arg3) = ARGIFY (arg3); \ ++ TYPEFY (arg2, __arg2) = ARGIFY (arg2); \ ++ TYPEFY (arg1, __arg1) = ARGIFY (arg1); \ ++ register TYPEFY (arg6, _a6) asm ("r9") = __arg6; \ ++ register TYPEFY (arg5, _a5) asm ("r8") = __arg5; \ ++ register TYPEFY (arg4, _a4) asm ("r10") = __arg4; \ ++ register TYPEFY (arg3, _a3) asm ("rdx") = __arg3; \ ++ register TYPEFY (arg2, _a2) asm ("rsi") = __arg2; \ ++ register TYPEFY (arg1, _a1) asm ("rdi") = __arg1; \ ++ asm volatile ( \ ++ "syscall\n\t" \ ++ : "=a" (resultvar) \ ++ : "0" (number), "r" (_a1), "r" (_a2), "r" (_a3), "r" (_a4), \ ++ "r" (_a5), "r" (_a6) \ ++ : "memory", REGISTERS_CLOBBERED_BY_SYSCALL); \ ++ (long int) resultvar; \ ++}) ++ ++# undef INTERNAL_SYSCALL_ERROR_P ++# define INTERNAL_SYSCALL_ERROR_P(val, err) \ ++ ((unsigned long int) (long int) (val) >= -4095L) ++ ++# undef INTERNAL_SYSCALL_ERRNO ++# define INTERNAL_SYSCALL_ERRNO(val, err) (-(val)) ++ ++/* List of system calls which are supported as vsyscalls. */ ++# define HAVE_CLOCK_GETTIME_VSYSCALL 1 ++# define HAVE_GETTIMEOFDAY_VSYSCALL 1 ++# define HAVE_GETCPU_VSYSCALL 1 ++ ++# define SINGLE_THREAD_BY_GLOBAL 1 ++ ++#endif /* __ASSEMBLER__ */ ++ ++ ++/* Pointer mangling support. */ ++#if IS_IN (rtld) ++/* We cannot use the thread descriptor because in ld.so we use setjmp ++ earlier than the descriptor is initialized. */ ++# ifdef __ASSEMBLER__ ++# define PTR_MANGLE(reg) xor __pointer_chk_guard_local(%rip), reg; \ ++ rol $2*LP_SIZE+1, reg ++# define PTR_DEMANGLE(reg) ror $2*LP_SIZE+1, reg; \ ++ xor __pointer_chk_guard_local(%rip), reg ++# else ++# define PTR_MANGLE(reg) asm ("xor __pointer_chk_guard_local(%%rip), %0\n" \ ++ "rol $2*" LP_SIZE "+1, %0" \ ++ : "=r" (reg) : "0" (reg)) ++# define PTR_DEMANGLE(reg) asm ("ror $2*" LP_SIZE "+1, %0\n" \ ++ "xor __pointer_chk_guard_local(%%rip), %0" \ ++ : "=r" (reg) : "0" (reg)) ++# endif ++#else ++# ifdef __ASSEMBLER__ ++# define PTR_MANGLE(reg) xor %fs:POINTER_GUARD, reg; \ ++ rol $2*LP_SIZE+1, reg ++# define PTR_DEMANGLE(reg) ror $2*LP_SIZE+1, reg; \ ++ xor %fs:POINTER_GUARD, reg ++# else ++# define PTR_MANGLE(var) asm ("xor %%fs:%c2, %0\n" \ ++ "rol $2*" LP_SIZE "+1, %0" \ ++ : "=r" (var) \ ++ : "0" (var), \ ++ "i" (offsetof (tcbhead_t, \ ++ pointer_guard))) ++# define PTR_DEMANGLE(var) asm ("ror $2*" LP_SIZE "+1, %0\n" \ ++ "xor %%fs:%c2, %0" \ ++ : "=r" (var) \ ++ : "0" (var), \ ++ "i" (offsetof (tcbhead_t, \ ++ pointer_guard))) ++# endif ++#endif ++ ++/* How to pass the off{64}_t argument on p{readv,writev}{64}. */ ++#undef LO_HI_LONG ++#define LO_HI_LONG(val) (val), 0 ++ ++/* Each shadow stack slot takes 8 bytes. Assuming that each stack ++ frame takes 256 bytes, this is used to compute shadow stack size ++ from stack size. */ ++#define STACK_SIZE_TO_SHADOW_STACK_SIZE_SHIFT 5 ++ ++#endif /* linux/x86_64/sysdep.h */ +diff --git a/nptl_2_17/sysdeps/unix/x86_64/sysdep_2_17.h b/nptl_2_17/sysdeps/unix/x86_64/sysdep_2_17.h +new file mode 100644 +index 00000000..5d61be20 +--- /dev/null ++++ b/nptl_2_17/sysdeps/unix/x86_64/sysdep_2_17.h +@@ -0,0 +1,34 @@ ++/* Copyright (C) 1991-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 ++ ++#ifdef __ASSEMBLER__ ++ ++/* This is defined as a separate macro so that other sysdep.h files ++ can include this one and then redefine DO_CALL. */ ++ ++#define DO_CALL(syscall_name, args) \ ++ lea SYS_ify (syscall_name), %rax; \ ++ syscall ++ ++#define r0 %rax /* Normal return-value register. */ ++#define r1 %rbx /* Secondary return-value register. */ ++#define MOVE(x,y) movq x, y ++ ++#endif /* __ASSEMBLER__ */ +diff --git a/nptl_2_17/sysdeps/x86/sysdep_2_17.h b/nptl_2_17/sysdeps/x86/sysdep_2_17.h +new file mode 100644 +index 00000000..9f319ea4 +--- /dev/null ++++ b/nptl_2_17/sysdeps/x86/sysdep_2_17.h +@@ -0,0 +1,104 @@ ++/* Assembler macros for x86. ++ 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 _X86_SYSDEP_H ++#define _X86_SYSDEP_H 1 ++ ++#include ++ ++/* __CET__ is defined by GCC with Control-Flow Protection values: ++ ++enum cf_protection_level ++{ ++ CF_NONE = 0, ++ CF_BRANCH = 1 << 0, ++ CF_RETURN = 1 << 1, ++ CF_FULL = CF_BRANCH | CF_RETURN, ++ CF_SET = 1 << 2 ++}; ++*/ ++ ++/* Set if CF_BRANCH (IBT) is enabled. */ ++#define X86_FEATURE_1_IBT (1U << 0) ++/* Set if CF_RETURN (SHSTK) is enabled. */ ++#define X86_FEATURE_1_SHSTK (1U << 1) ++ ++#ifdef __CET__ ++# define CET_ENABLED 1 ++# define IBT_ENABLED (__CET__ & X86_FEATURE_1_IBT) ++# define SHSTK_ENABLED (__CET__ & X86_FEATURE_1_SHSTK) ++#else ++# define CET_ENABLED 0 ++# define IBT_ENABLED 0 ++# define SHSTK_ENABLED 0 ++#endif ++ ++#ifdef __ASSEMBLER__ ++ ++/* Syntactic details of assembler. */ ++ ++#ifdef _CET_ENDBR ++# define _CET_NOTRACK notrack ++#else ++# define _CET_ENDBR ++# define _CET_NOTRACK ++#endif ++ ++/* ELF uses byte-counts for .align, most others use log2 of count of bytes. */ ++#define ALIGNARG(log2) 1<. */ ++ ++#ifndef _BITS_PTHREADTYPES_ARCH_H ++#define _BITS_PTHREADTYPES_ARCH_H 1 ++ ++#include ++ ++#ifdef __x86_64__ ++# if __WORDSIZE == 64 ++# define __SIZEOF_PTHREAD_MUTEX_T 40 ++# define __SIZEOF_PTHREAD_ATTR_T 56 ++# define __SIZEOF_PTHREAD_MUTEX_T 40 ++# define __SIZEOF_PTHREAD_RWLOCK_T 56 ++# define __SIZEOF_PTHREAD_BARRIER_T 32 ++# else ++# define __SIZEOF_PTHREAD_MUTEX_T 32 ++# define __SIZEOF_PTHREAD_ATTR_T 32 ++# define __SIZEOF_PTHREAD_MUTEX_T 32 ++# define __SIZEOF_PTHREAD_RWLOCK_T 44 ++# define __SIZEOF_PTHREAD_BARRIER_T 20 ++# endif ++#else ++# define __SIZEOF_PTHREAD_MUTEX_T 24 ++# define __SIZEOF_PTHREAD_ATTR_T 36 ++# define __SIZEOF_PTHREAD_MUTEX_T 24 ++# define __SIZEOF_PTHREAD_RWLOCK_T 32 ++# define __SIZEOF_PTHREAD_BARRIER_T 20 ++#endif ++#define __SIZEOF_PTHREAD_MUTEXATTR_T 4 ++#define __SIZEOF_PTHREAD_COND_T 48 ++#define __SIZEOF_PTHREAD_CONDATTR_T 4 ++#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 ++#define __SIZEOF_PTHREAD_BARRIERATTR_T 4 ++ ++/* Definitions for internal mutex struct. */ ++#define __PTHREAD_COMPAT_PADDING_MID ++#define __PTHREAD_COMPAT_PADDING_END ++#define __PTHREAD_MUTEX_LOCK_ELISION 1 ++#ifdef __x86_64__ ++# define __PTHREAD_MUTEX_NUSERS_AFTER_KIND 0 ++# define __PTHREAD_MUTEX_USE_UNION 0 ++#else ++# define __PTHREAD_MUTEX_NUSERS_AFTER_KIND 1 ++# define __PTHREAD_MUTEX_USE_UNION 1 ++#endif ++ ++#define __LOCK_ALIGNMENT ++#define __ONCE_ALIGNMENT ++ ++struct __pthread_rwlock_arch_t ++{ ++ unsigned int __readers; ++ unsigned int __writers; ++ unsigned int __wrphase_futex; ++ unsigned int __writers_futex; ++ unsigned int __pad3; ++ unsigned int __pad4; ++#ifdef __x86_64__ ++ int __cur_writer; ++ int __shared; ++ signed char __rwelision; ++# ifdef __ILP32__ ++ unsigned char __pad1[3]; ++# define __PTHREAD_RWLOCK_ELISION_EXTRA 0, { 0, 0, 0 } ++# else ++ unsigned char __pad1[7]; ++# define __PTHREAD_RWLOCK_ELISION_EXTRA 0, { 0, 0, 0, 0, 0, 0, 0 } ++# endif ++ unsigned long int __pad2; ++ /* FLAGS must stay at this position in the structure to maintain ++ binary compatibility. */ ++ unsigned int __flags; ++# define __PTHREAD_RWLOCK_INT_FLAGS_SHARED 1 ++#else ++ /* FLAGS must stay at this position in the structure to maintain ++ binary compatibility. */ ++ unsigned char __flags; ++ unsigned char __shared; ++ signed char __rwelision; ++# define __PTHREAD_RWLOCK_ELISION_EXTRA 0 ++ unsigned char __pad2; ++ int __cur_writer; ++#endif ++}; ++ ++#ifndef __x86_64__ ++/* Extra attributes for the cleanup functions. */ ++# define __cleanup_fct_attribute __attribute__ ((__regparm__ (1))) ++#endif ++ ++#endif /* bits/pthreadtypes.h */ +diff --git a/nptl_2_17/sysdeps/x86_64/sysdep_2_17.h b/nptl_2_17/sysdeps/x86_64/sysdep_2_17.h +new file mode 100644 +index 00000000..ab1b6bea +--- /dev/null ++++ b/nptl_2_17/sysdeps/x86_64/sysdep_2_17.h +@@ -0,0 +1,129 @@ ++/* Assembler macros for x86-64. ++ Copyright (C) 2001-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 _X86_64_SYSDEP_H ++#define _X86_64_SYSDEP_H 1 ++ ++#include ++ ++#ifdef __ASSEMBLER__ ++ ++/* Syntactic details of assembler. */ ++ ++/* This macro is for setting proper CFI with DW_CFA_expression describing ++ the register as saved relative to %rsp instead of relative to the CFA. ++ Expression is DW_OP_drop, DW_OP_breg7 (%rsp is register 7), sleb128 offset ++ from %rsp. */ ++#define cfi_offset_rel_rsp(regn, off) .cfi_escape 0x10, regn, 0x4, 0x13, \ ++ 0x77, off & 0x7F | 0x80, off >> 7 ++ ++/* If compiled for profiling, call `mcount' at the start of each function. */ ++#ifdef PROF ++/* The mcount code relies on a normal frame pointer being on the stack ++ to locate our caller, so push one just for its benefit. */ ++#define CALL_MCOUNT \ ++ pushq %rbp; \ ++ cfi_adjust_cfa_offset(8); \ ++ movq %rsp, %rbp; \ ++ cfi_def_cfa_register(%rbp); \ ++ call JUMPTARGET(mcount); \ ++ popq %rbp; \ ++ cfi_def_cfa(rsp,8); ++#else ++#define CALL_MCOUNT /* Do nothing. */ ++#endif ++ ++#define PSEUDO(name, syscall_name, args) \ ++lose: \ ++ jmp JUMPTARGET(syscall_error) \ ++ .globl syscall_error; \ ++ ENTRY (name) \ ++ DO_CALL (syscall_name, args); \ ++ jb lose ++ ++#undef JUMPTARGET ++#ifdef SHARED ++# ifdef BIND_NOW ++# define JUMPTARGET(name) *name##@GOTPCREL(%rip) ++# else ++# define JUMPTARGET(name) name##@PLT ++# endif ++#else ++/* For static archives, branch to target directly. */ ++# define JUMPTARGET(name) name ++#endif ++ ++/* Long and pointer size in bytes. */ ++#define LP_SIZE 8 ++ ++/* Instruction to operate on long and pointer. */ ++#define LP_OP(insn) insn##q ++ ++/* Assembler address directive. */ ++#define ASM_ADDR .quad ++ ++/* Registers to hold long and pointer. */ ++#define RAX_LP rax ++#define RBP_LP rbp ++#define RBX_LP rbx ++#define RCX_LP rcx ++#define RDI_LP rdi ++#define RDX_LP rdx ++#define RSI_LP rsi ++#define RSP_LP rsp ++#define R8_LP r8 ++#define R9_LP r9 ++#define R10_LP r10 ++#define R11_LP r11 ++#define R12_LP r12 ++#define R13_LP r13 ++#define R14_LP r14 ++#define R15_LP r15 ++ ++#else /* __ASSEMBLER__ */ ++ ++/* Long and pointer size in bytes. */ ++#define LP_SIZE "8" ++ ++/* Instruction to operate on long and pointer. */ ++#define LP_OP(insn) #insn "q" ++ ++/* Assembler address directive. */ ++#define ASM_ADDR ".quad" ++ ++/* Registers to hold long and pointer. */ ++#define RAX_LP "rax" ++#define RBP_LP "rbp" ++#define RBX_LP "rbx" ++#define RCX_LP "rcx" ++#define RDI_LP "rdi" ++#define RDX_LP "rdx" ++#define RSI_LP "rsi" ++#define RSP_LP "rsp" ++#define R8_LP "r8" ++#define R9_LP "r9" ++#define R10_LP "r10" ++#define R11_LP "r11" ++#define R12_LP "r12" ++#define R13_LP "r13" ++#define R14_LP "r14" ++#define R15_LP "r15" ++ ++#endif /* __ASSEMBLER__ */ ++ ++#endif /* _X86_64_SYSDEP_H */ +diff --git a/nptl_2_17/thread_db_2_17.h b/nptl_2_17/thread_db_2_17.h +new file mode 100644 +index 00000000..4206aed0 +--- /dev/null ++++ b/nptl_2_17/thread_db_2_17.h +@@ -0,0 +1,458 @@ ++/* thread_db.h -- interface to libthread_db.so library for debugging -lpthread ++ 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 ++ . */ ++ ++#ifndef _THREAD_DB_H ++#define _THREAD_DB_H 1 ++ ++/* This is the debugger interface for the NPTL library. It is ++ modelled closely after the interface with same names in Solaris ++ with the goal to share the same code in the debugger. */ ++#include ++#include ++#include ++#include ++ ++ ++/* Error codes of the library. */ ++typedef enum ++{ ++ TD_OK, /* No error. */ ++ TD_ERR, /* No further specified error. */ ++ TD_NOTHR, /* No matching thread found. */ ++ TD_NOSV, /* No matching synchronization handle found. */ ++ TD_NOLWP, /* No matching light-weighted process found. */ ++ TD_BADPH, /* Invalid process handle. */ ++ TD_BADTH, /* Invalid thread handle. */ ++ TD_BADSH, /* Invalid synchronization handle. */ ++ TD_BADTA, /* Invalid thread agent. */ ++ TD_BADKEY, /* Invalid key. */ ++ TD_NOMSG, /* No event available. */ ++ TD_NOFPREGS, /* No floating-point register content available. */ ++ TD_NOLIBTHREAD, /* Application not linked with thread library. */ ++ TD_NOEVENT, /* Requested event is not supported. */ ++ TD_NOCAPAB, /* Capability not available. */ ++ TD_DBERR, /* Internal debug library error. */ ++ TD_NOAPLIC, /* Operation is not applicable. */ ++ TD_NOTSD, /* No thread-specific data available. */ ++ TD_MALLOC, /* Out of memory. */ ++ TD_PARTIALREG, /* Not entire register set was read or written. */ ++ TD_NOXREGS, /* X register set not available for given thread. */ ++ TD_TLSDEFER, /* Thread has not yet allocated TLS for given module. */ ++ TD_NOTALLOC = TD_TLSDEFER, ++ TD_VERSION, /* Version if libpthread and libthread_db do not match. */ ++ TD_NOTLS /* There is no TLS segment in the given module. */ ++} td_err_e; ++ ++ ++/* Possible thread states. TD_THR_ANY_STATE is a pseudo-state used to ++ select threads regardless of state in td_ta_thr_iter(). */ ++typedef enum ++{ ++ TD_THR_ANY_STATE, ++ TD_THR_UNKNOWN, ++ TD_THR_STOPPED, ++ TD_THR_RUN, ++ TD_THR_ACTIVE, ++ TD_THR_ZOMBIE, ++ TD_THR_SLEEP, ++ TD_THR_STOPPED_ASLEEP ++} td_thr_state_e; ++ ++/* Thread type: user or system. TD_THR_ANY_TYPE is a pseudo-type used ++ to select threads regardless of type in td_ta_thr_iter(). */ ++typedef enum ++{ ++ TD_THR_ANY_TYPE, ++ TD_THR_USER, ++ TD_THR_SYSTEM ++} td_thr_type_e; ++ ++ ++/* Types of the debugging library. */ ++ ++/* Handle for a process. This type is opaque. */ ++typedef struct td_thragent td_thragent_t; ++ ++/* The actual thread handle type. This is also opaque. */ ++typedef struct td_thrhandle ++{ ++ td_thragent_t *th_ta_p; ++ psaddr_t th_unique; ++} td_thrhandle_t; ++ ++ ++/* Forward declaration of a type defined by and for the dynamic linker. */ ++struct link_map; ++ ++ ++/* Flags for `td_ta_thr_iter'. */ ++#define TD_THR_ANY_USER_FLAGS 0xffffffff ++#define TD_THR_LOWEST_PRIORITY -20 ++#define TD_SIGNO_MASK NULL ++ ++ ++#define TD_EVENTSIZE 2 ++#define BT_UISHIFT 5 /* log base 2 of BT_NBIPUI, to extract word index */ ++#define BT_NBIPUI (1 << BT_UISHIFT) /* n bits per unsigned int */ ++#define BT_UIMASK (BT_NBIPUI - 1) /* to extract bit index */ ++ ++/* Bitmask of enabled events. */ ++typedef struct td_thr_events ++{ ++ uint32_t event_bits[TD_EVENTSIZE]; ++} td_thr_events_t; ++ ++/* Event set manipulation macros. */ ++#define __td_eventmask(n) \ ++ (UINT32_C (1) << (((n) - 1) & BT_UIMASK)) ++#define __td_eventword(n) \ ++ ((UINT32_C ((n) - 1)) >> BT_UISHIFT) ++ ++#define td_event_emptyset(setp) \ ++ do { \ ++ int __i; \ ++ for (__i = TD_EVENTSIZE; __i > 0; --__i) \ ++ (setp)->event_bits[__i - 1] = 0; \ ++ } while (0) ++ ++#define td_event_fillset(setp) \ ++ do { \ ++ int __i; \ ++ for (__i = TD_EVENTSIZE; __i > 0; --__i) \ ++ (setp)->event_bits[__i - 1] = UINT32_C (0xffffffff); \ ++ } while (0) ++ ++#define td_event_addset(setp, n) \ ++ (((setp)->event_bits[__td_eventword (n)]) |= __td_eventmask (n)) ++#define td_event_delset(setp, n) \ ++ (((setp)->event_bits[__td_eventword (n)]) &= ~__td_eventmask (n)) ++#define td_eventismember(setp, n) \ ++ (__td_eventmask (n) & ((setp)->event_bits[__td_eventword (n)])) ++#if TD_EVENTSIZE == 2 ++# define td_eventisempty(setp) \ ++ (!((setp)->event_bits[0]) && !((setp)->event_bits[1])) ++#else ++# error "td_eventisempty must be changed to match TD_EVENTSIZE" ++#endif ++ ++/* Events reportable by the thread implementation. */ ++typedef enum ++{ ++ TD_ALL_EVENTS, /* Pseudo-event number. */ ++ TD_EVENT_NONE = TD_ALL_EVENTS, /* Depends on context. */ ++ TD_READY, /* Is executable now. */ ++ TD_SLEEP, /* Blocked in a synchronization obj. */ ++ TD_SWITCHTO, /* Now assigned to a process. */ ++ TD_SWITCHFROM, /* Not anymore assigned to a process. */ ++ TD_LOCK_TRY, /* Trying to get an unavailable lock. */ ++ TD_CATCHSIG, /* Signal posted to the thread. */ ++ TD_IDLE, /* Process getting idle. */ ++ TD_CREATE, /* New thread created. */ ++ TD_DEATH, /* Thread terminated. */ ++ TD_PREEMPT, /* Preempted. */ ++ TD_PRI_INHERIT, /* Inherited elevated priority. */ ++ TD_REAP, /* Reaped. */ ++ TD_CONCURRENCY, /* Number of processes changing. */ ++ TD_TIMEOUT, /* Conditional variable wait timed out. */ ++ TD_MIN_EVENT_NUM = TD_READY, ++ TD_MAX_EVENT_NUM = TD_TIMEOUT, ++ TD_EVENTS_ENABLE = 31 /* Event reporting enabled. */ ++} td_event_e; ++ ++/* Values representing the different ways events are reported. */ ++typedef enum ++{ ++ NOTIFY_BPT, /* User must insert breakpoint at u.bptaddr. */ ++ NOTIFY_AUTOBPT, /* Breakpoint at u.bptaddr is automatically ++ inserted. */ ++ NOTIFY_SYSCALL /* System call u.syscallno will be invoked. */ ++} td_notify_e; ++ ++/* Description how event type is reported. */ ++typedef struct td_notify ++{ ++ td_notify_e type; /* Way the event is reported. */ ++ union ++ { ++ psaddr_t bptaddr; /* Address of breakpoint. */ ++ int syscallno; /* Number of system call used. */ ++ } u; ++} td_notify_t; ++ ++/* Structure used to report event. */ ++typedef struct td_event_msg ++{ ++ td_event_e event; /* Event type being reported. */ ++ const td_thrhandle_t *th_p; /* Thread reporting the event. */ ++ union ++ { ++# if 0 ++ td_synchandle_t *sh; /* Handle of synchronization object. */ ++#endif ++ uintptr_t data; /* Event specific data. */ ++ } msg; ++} td_event_msg_t; ++ ++/* Structure containing event data available in each thread structure. */ ++typedef struct ++{ ++ td_thr_events_t eventmask; /* Mask of enabled events. */ ++ td_event_e eventnum; /* Number of last event. */ ++ void *eventdata; /* Data associated with event. */ ++} td_eventbuf_t; ++ ++ ++/* Gathered statistics about the process. */ ++typedef struct td_ta_stats ++{ ++ int nthreads; /* Total number of threads in use. */ ++ int r_concurrency; /* Concurrency level requested by user. */ ++ int nrunnable_num; /* Average runnable threads, numerator. */ ++ int nrunnable_den; /* Average runnable threads, denominator. */ ++ int a_concurrency_num; /* Achieved concurrency level, numerator. */ ++ int a_concurrency_den; /* Achieved concurrency level, denominator. */ ++ int nlwps_num; /* Average number of processes in use, ++ numerator. */ ++ int nlwps_den; /* Average number of processes in use, ++ denominator. */ ++ int nidle_num; /* Average number of idling processes, ++ numerator. */ ++ int nidle_den; /* Average number of idling processes, ++ denominator. */ ++} td_ta_stats_t; ++ ++ ++/* Since Sun's library is based on Solaris threads we have to define a few ++ types to map them to POSIX threads. */ ++typedef pthread_t thread_t; ++typedef pthread_key_t thread_key_t; ++ ++ ++/* Callback for iteration over threads. */ ++typedef int td_thr_iter_f (const td_thrhandle_t *, void *); ++ ++/* Callback for iteration over thread local data. */ ++typedef int td_key_iter_f (thread_key_t, void (*) (void *), void *); ++ ++ ++ ++/* Forward declaration. This has to be defined by the user. */ ++struct ps_prochandle; ++ ++ ++/* Information about the thread. */ ++typedef struct td_thrinfo ++{ ++ td_thragent_t *ti_ta_p; /* Process handle. */ ++ unsigned int ti_user_flags; /* Unused. */ ++ thread_t ti_tid; /* Thread ID returned by ++ pthread_create(). */ ++ char *ti_tls; /* Pointer to thread-local data. */ ++ psaddr_t ti_startfunc; /* Start function passed to ++ pthread_create(). */ ++ psaddr_t ti_stkbase; /* Base of thread's stack. */ ++ long int ti_stksize; /* Size of thread's stack. */ ++ psaddr_t ti_ro_area; /* Unused. */ ++ int ti_ro_size; /* Unused. */ ++ td_thr_state_e ti_state; /* Thread state. */ ++ unsigned char ti_db_suspended; /* Nonzero if suspended by debugger. */ ++ td_thr_type_e ti_type; /* Type of the thread (system vs ++ user thread). */ ++ intptr_t ti_pc; /* Unused. */ ++ intptr_t ti_sp; /* Unused. */ ++ short int ti_flags; /* Unused. */ ++ int ti_pri; /* Thread priority. */ ++ lwpid_t ti_lid; /* Kernel PID for this thread. */ ++ sigset_t ti_sigmask; /* Signal mask. */ ++ unsigned char ti_traceme; /* Nonzero if event reporting ++ enabled. */ ++ unsigned char ti_preemptflag; /* Unused. */ ++ unsigned char ti_pirecflag; /* Unused. */ ++ sigset_t ti_pending; /* Set of pending signals. */ ++ td_thr_events_t ti_events; /* Set of enabled events. */ ++} td_thrinfo_t; ++ ++ ++ ++/* Prototypes for exported library functions. */ ++ ++/* Initialize the thread debug support library. */ ++extern td_err_e td_init (void); ++ ++/* Historical relict. Should not be used anymore. */ ++extern td_err_e td_log (void); ++ ++/* Return list of symbols the library can request. */ ++extern const char **td_symbol_list (void); ++ ++/* Generate new thread debug library handle for process PS. */ ++extern td_err_e td_ta_new (struct ps_prochandle *__ps, td_thragent_t **__ta); ++ ++/* Free resources allocated for TA. */ ++extern td_err_e td_ta_delete (td_thragent_t *__ta); ++ ++/* Get number of currently running threads in process associated with TA. */ ++extern td_err_e td_ta_get_nthreads (const td_thragent_t *__ta, int *__np); ++ ++/* Return process handle passed in `td_ta_new' for process associated with ++ TA. */ ++extern td_err_e td_ta_get_ph (const td_thragent_t *__ta, ++ struct ps_prochandle **__ph); ++ ++/* Map thread library handle PT to thread debug library handle for process ++ associated with TA and store result in *TH. */ ++extern td_err_e td_ta_map_id2thr (const td_thragent_t *__ta, pthread_t __pt, ++ td_thrhandle_t *__th); ++ ++/* Map process ID LWPID to thread debug library handle for process ++ associated with TA and store result in *TH. */ ++extern td_err_e td_ta_map_lwp2thr (const td_thragent_t *__ta, lwpid_t __lwpid, ++ td_thrhandle_t *__th); ++ ++ ++/* Call for each thread in a process associated with TA the callback function ++ CALLBACK. */ ++extern td_err_e td_ta_thr_iter (const td_thragent_t *__ta, ++ td_thr_iter_f *__callback, void *__cbdata_p, ++ td_thr_state_e __state, int __ti_pri, ++ sigset_t *__ti_sigmask_p, ++ unsigned int __ti_user_flags); ++ ++/* Call for each defined thread local data entry the callback function KI. */ ++extern td_err_e td_ta_tsd_iter (const td_thragent_t *__ta, td_key_iter_f *__ki, ++ void *__p); ++ ++ ++/* Get event address for EVENT. */ ++extern td_err_e td_ta_event_addr (const td_thragent_t *__ta, ++ td_event_e __event, td_notify_t *__ptr); ++ ++/* Enable EVENT in global mask. */ ++extern td_err_e td_ta_set_event (const td_thragent_t *__ta, ++ td_thr_events_t *__event); ++ ++/* Disable EVENT in global mask. */ ++extern td_err_e td_ta_clear_event (const td_thragent_t *__ta, ++ td_thr_events_t *__event); ++ ++/* Return information about last event. */ ++extern td_err_e td_ta_event_getmsg (const td_thragent_t *__ta, ++ td_event_msg_t *__msg); ++ ++ ++/* Set suggested concurrency level for process associated with TA. */ ++extern td_err_e td_ta_setconcurrency (const td_thragent_t *__ta, int __level); ++ ++ ++/* Enable collecting statistics for process associated with TA. */ ++extern td_err_e td_ta_enable_stats (const td_thragent_t *__ta, int __enable); ++ ++/* Reset statistics. */ ++extern td_err_e td_ta_reset_stats (const td_thragent_t *__ta); ++ ++/* Retrieve statistics from process associated with TA. */ ++extern td_err_e td_ta_get_stats (const td_thragent_t *__ta, ++ td_ta_stats_t *__statsp); ++ ++ ++/* Validate that TH is a thread handle. */ ++extern td_err_e td_thr_validate (const td_thrhandle_t *__th); ++ ++/* Return information about thread TH. */ ++extern td_err_e td_thr_get_info (const td_thrhandle_t *__th, ++ td_thrinfo_t *__infop); ++ ++/* Retrieve floating-point register contents of process running thread TH. */ ++extern td_err_e td_thr_getfpregs (const td_thrhandle_t *__th, ++ prfpregset_t *__regset); ++ ++/* Retrieve general register contents of process running thread TH. */ ++extern td_err_e td_thr_getgregs (const td_thrhandle_t *__th, ++ prgregset_t __gregs); ++ ++/* Retrieve extended register contents of process running thread TH. */ ++extern td_err_e td_thr_getxregs (const td_thrhandle_t *__th, void *__xregs); ++ ++/* Get size of extended register set of process running thread TH. */ ++extern td_err_e td_thr_getxregsize (const td_thrhandle_t *__th, int *__sizep); ++ ++/* Set floating-point register contents of process running thread TH. */ ++extern td_err_e td_thr_setfpregs (const td_thrhandle_t *__th, ++ const prfpregset_t *__fpregs); ++ ++/* Set general register contents of process running thread TH. */ ++extern td_err_e td_thr_setgregs (const td_thrhandle_t *__th, ++ prgregset_t __gregs); ++ ++/* Set extended register contents of process running thread TH. */ ++extern td_err_e td_thr_setxregs (const td_thrhandle_t *__th, ++ const void *__addr); ++ ++ ++/* Get address of the given module's TLS storage area for the given thread. */ ++extern td_err_e td_thr_tlsbase (const td_thrhandle_t *__th, ++ unsigned long int __modid, ++ psaddr_t *__base); ++ ++/* Get address of thread local variable. */ ++extern td_err_e td_thr_tls_get_addr (const td_thrhandle_t *__th, ++ psaddr_t __map_address, size_t __offset, ++ psaddr_t *__address); ++ ++ ++/* Enable reporting for EVENT for thread TH. */ ++extern td_err_e td_thr_event_enable (const td_thrhandle_t *__th, int __event); ++ ++/* Enable EVENT for thread TH. */ ++extern td_err_e td_thr_set_event (const td_thrhandle_t *__th, ++ td_thr_events_t *__event); ++ ++/* Disable EVENT for thread TH. */ ++extern td_err_e td_thr_clear_event (const td_thrhandle_t *__th, ++ td_thr_events_t *__event); ++ ++/* Get event message for thread TH. */ ++extern td_err_e td_thr_event_getmsg (const td_thrhandle_t *__th, ++ td_event_msg_t *__msg); ++ ++ ++/* Set priority of thread TH. */ ++extern td_err_e td_thr_setprio (const td_thrhandle_t *__th, int __prio); ++ ++ ++/* Set pending signals for thread TH. */ ++extern td_err_e td_thr_setsigpending (const td_thrhandle_t *__th, ++ unsigned char __n, const sigset_t *__ss); ++ ++/* Set signal mask for thread TH. */ ++extern td_err_e td_thr_sigsetmask (const td_thrhandle_t *__th, ++ const sigset_t *__ss); ++ ++ ++/* Return thread local data associated with key TK in thread TH. */ ++extern td_err_e td_thr_tsd (const td_thrhandle_t *__th, ++ const thread_key_t __tk, void **__data); ++ ++ ++/* Suspend execution of thread TH. */ ++extern td_err_e td_thr_dbsuspend (const td_thrhandle_t *__th); ++ ++/* Resume execution of thread TH. */ ++extern td_err_e td_thr_dbresume (const td_thrhandle_t *__th); ++ ++#endif /* thread_db.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..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/glibc.spec b/glibc.spec index edc7cc487c4325a05788cdd2827cec61144eb1b1..e824ab59d166081935fb44142745529642cc6b31 100644 --- a/glibc.spec +++ b/glibc.spec @@ -31,7 +31,9 @@ %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 @@ -63,7 +65,7 @@ ############################################################################## Name: glibc Version: 2.34 -Release: 14 +Release: 15 Summary: The GNU libc libraries License: %{all_license} URL: http://www.gnu.org/software/glibc/ @@ -117,7 +119,7 @@ Patch32: rtld-copy-terminating-null-in-tunables_strdup-bug-28.patch #Patch9000: turn-REP_STOSB_THRESHOLD-from-2k-to-1M.patch Patch9001: delete-no-hard-link-to-avoid-all_language-package-to.patch -#Patch9002: build-extra-libpthreadcond-so.patch +Patch9002: compat-2.17-libpthreadcond-so.patch Provides: ldconfig rtld(GNU_HASH) bundled(gnulib) @@ -409,6 +411,18 @@ Requires: man info %description help This package provides al doc and man 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. ############################################################################## @@ -507,11 +521,11 @@ 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 @@ -528,10 +542,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 \ @@ -591,6 +601,11 @@ 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 compat-2.17 +%if %{with compat_2_17} +install -p -m 755 build-%{target}/nptl/libpthread-2.17.so $RPM_BUILD_ROOT%{_libdir} +%endif + # This is for ncsd - in glibc 2.2 install -m 644 nscd/nscd.conf $RPM_BUILD_ROOT/etc mkdir -p $RPM_BUILD_ROOT%{_tmpfilesdir} @@ -703,6 +718,9 @@ touch libnsl.filelist touch debugutils.filelist touch benchtests.filelist touch debuginfo.filelist +%if %{with compat_2_17} +touch compat-2.17.filelist +%endif { find $RPM_BUILD_ROOT \( -type f -o -type l \) \ @@ -729,6 +747,9 @@ touch debuginfo.filelist -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' \ +%if %{with compat_2_17} + -e '\,.*/%{_libdir}/libpthread-2.17.so,d' \ +%endif -e '\,.*/bin/\(memusage\|mtrace\|xtrace\|pcprofiledump\),d' } | sort > master.filelist @@ -765,10 +786,6 @@ for module in compat files dns; do done grep -e "libmemusage.so" -e "libpcprofile.so" master.filelist >> glibc.filelist -%if %{with libpthreadcond} - echo "%{_libdir}/libpthreadcond.so" >> glibc.filelist -%endif - ############################################################################## # glibc "common" sub-package ############################################################################## @@ -863,6 +880,13 @@ echo "%{_prefix}/libexec/glibc-benchtests/import_bench.py*" >> benchtests.fileli echo "%{_prefix}/libexec/glibc-benchtests/validate_benchout.py*" >> benchtests.filelist %endif +%if %{with compat_2_17} +############################################################################## +# glibc compat-2.17 sub-package +############################################################################## + echo "%{_libdir}/libpthread-2.17.so" >> compat-2.17.filelist +%endif + %if 0%{?_enable_debug_packages} ############################################################################## # glibc debuginfo sub-package @@ -881,6 +905,9 @@ find_debuginfo_args="$find_debuginfo_args \ -l glibc.filelist \ %if %{with benchtests} -l benchtests.filelist +%endif +%if %{with compat_2_17} + -l compat-2.17.filelist \ %endif " %endif @@ -1273,7 +1300,16 @@ 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 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.