9559 lines
338 KiB
Diff
9559 lines
338 KiB
Diff
|
|
commit a88c9263686012ca2a336379b7d66e59dea2b43b
|
||
|
|
Author: Ulrich Drepper <drepper@redhat.com>
|
||
|
|
Date: Wed Feb 5 09:54:24 2003 +0000
|
||
|
|
Subject: [PATCH] build extra lipthreadcond so
|
||
|
|
|
||
|
|
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 | 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_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/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
|
||
|
|
create mode 100644 nptl_2_17/pthread_cond_destroy_2_17.c
|
||
|
|
create mode 100644 nptl_2_17/pthread_cond_init_2_17.c
|
||
|
|
create mode 100644 nptl_2_17/pthread_cond_signal_2_17.c
|
||
|
|
create mode 100644 nptl_2_17/pthread_cond_timedwait_2_17.c
|
||
|
|
create mode 100644 nptl_2_17/pthread_cond_wait_2_17.c
|
||
|
|
create mode 100644 nptl_2_17/pthread_condattr_getclock_2_17.c
|
||
|
|
create mode 100644 nptl_2_17/pthread_condattr_getpshared_2_17.c
|
||
|
|
create mode 100644 nptl_2_17/pthread_condattr_init_2_17.c
|
||
|
|
create mode 100644 nptl_2_17/pthread_condattr_setclock_2_17.c
|
||
|
|
create mode 100644 nptl_2_17/pthread_mutex_cond_lock_2_17.c
|
||
|
|
create mode 100644 nptl_2_17/pthread_mutex_lock_2_17.c
|
||
|
|
create mode 100644 nptl_2_17/pthread_mutex_unlock_2_17.c
|
||
|
|
create mode 100644 nptl_2_17/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/vars_2_17.c
|
||
|
|
|
||
|
|
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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#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 <bits/pthreadtypes-arch_2_17.h>
|
||
|
|
+
|
||
|
|
+/* 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 <drepper@redhat.com>, 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include <sysdep_2_17.h>
|
||
|
|
+#include <descr_2_17.h>
|
||
|
|
+#include "pthreadP_2_17.h"
|
||
|
|
+#include <setjmp.h>
|
||
|
|
+#include <stdlib.h>
|
||
|
|
+#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 <drepper@redhat.com>, 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include "pthreadP_2_17.h"
|
||
|
|
+#include <stdlib.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/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 <drepper@redhat.com>, 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#ifndef _DESCR_H
|
||
|
|
+#define _DESCR_H 1
|
||
|
|
+
|
||
|
|
+#include <limits.h>
|
||
|
|
+#include <sched.h>
|
||
|
|
+#include <setjmp.h>
|
||
|
|
+#include <stdbool.h>
|
||
|
|
+#include <sys/types.h>
|
||
|
|
+#include <hp-timing.h>
|
||
|
|
+#include <list_t.h>
|
||
|
|
+#include <lowlevellock_2_17.h>
|
||
|
|
+#include <pthreaddef.h>
|
||
|
|
+#include <dl-sysdep.h>
|
||
|
|
+#include "thread_db_2_17.h"
|
||
|
|
+#include <tls.h>
|
||
|
|
+#include <unwind.h>
|
||
|
|
+#include <bits/types/res_state.h>
|
||
|
|
+#include <kernel-features.h>
|
||
|
|
+
|
||
|
|
+#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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include "config.h"
|
||
|
|
+#include <pthreadP_2_17.h>
|
||
|
|
+#include <init-arch.h>
|
||
|
|
+#include <elision-conf_2_17.h>
|
||
|
|
+#include <unistd.h>
|
||
|
|
+
|
||
|
|
+# define TUNABLE_NAMESPACE elision
|
||
|
|
+# define TOP_NAMESPACE glibc
|
||
|
|
+#include <elf/dl-tunables.h>
|
||
|
|
+
|
||
|
|
+/* 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+#ifndef _ELISION_CONF_H
|
||
|
|
+#define _ELISION_CONF_H 1
|
||
|
|
+
|
||
|
|
+#include <pthread_2_17.h>
|
||
|
|
+#include <time.h>
|
||
|
|
+
|
||
|
|
+/* 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include <pthread_2_17.h>
|
||
|
|
+#include "pthreadP_2_17.h"
|
||
|
|
+#include "lowlevellock_2_17.h"
|
||
|
|
+#include "hle_2_17.h"
|
||
|
|
+#include <elision-conf_2_17.h>
|
||
|
|
+
|
||
|
|
+#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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include <time.h>
|
||
|
|
+#include <elision-conf_2_17.h>
|
||
|
|
+#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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include <pthread_2_17.h>
|
||
|
|
+#include <pthreadP_2_17.h>
|
||
|
|
+#include <lowlevellock_2_17.h>
|
||
|
|
+#include "hle_2_17.h"
|
||
|
|
+#include <elision-conf_2_17.h>
|
||
|
|
+
|
||
|
|
+#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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#ifndef FUTEX_INTERNAL_H
|
||
|
|
+#define FUTEX_INTERNAL_H
|
||
|
|
+
|
||
|
|
+#include <sysdeps/nptl/futex-internal_2_17.h>
|
||
|
|
+#include <errno.h>
|
||
|
|
+#include <lowlevellock-futex_2_17.h>
|
||
|
|
+#include <pthreadP_2_17.h>
|
||
|
|
+
|
||
|
|
+/* 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 <drepper@redhat.com>, 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#ifndef _INTERNALTYPES_H
|
||
|
|
+#define _INTERNALTYPES_H 1
|
||
|
|
+
|
||
|
|
+#include <stdint.h>
|
||
|
|
+#include <atomic.h>
|
||
|
|
+#include <endian.h>
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+/* 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 <paulus@au.ibm.com>, 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include <atomic.h>
|
||
|
|
+#include <errno.h>
|
||
|
|
+#include <lowlevellock_2_17.h>
|
||
|
|
+#include <sys/time.h>
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+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 <paulus@au.ibm.com>, 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include <errno.h>
|
||
|
|
+#include <sysdep_2_17.h>
|
||
|
|
+#include <lowlevellock_2_17.h>
|
||
|
|
+#include <sys/time.h>
|
||
|
|
+#include <atomic.h>
|
||
|
|
+
|
||
|
|
+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 <drepper@redhat.com>, 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#ifndef _PTHREAD_FUNCTIONS_H
|
||
|
|
+#define _PTHREAD_FUNCTIONS_H 1
|
||
|
|
+
|
||
|
|
+#include <pthread_2_17.h>
|
||
|
|
+#include <internaltypes_2_17.h>
|
||
|
|
+#include <sysdep_2_17.h>
|
||
|
|
+#include <setjmp.h>
|
||
|
|
+
|
||
|
|
+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 <drepper@redhat.com>, 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#ifndef _PTHREADP_H
|
||
|
|
+#define _PTHREADP_H 1
|
||
|
|
+
|
||
|
|
+#include "kernel-features_2_17.h"
|
||
|
|
+#include "pthread_2_17.h"
|
||
|
|
+#include <sysdep_2_17.h>
|
||
|
|
+#include "internaltypes_2_17.h"
|
||
|
|
+#include <pthread-functions_2_17.h>
|
||
|
|
+#include "descr_2_17.h"
|
||
|
|
+#include <lowlevellock_2_17.h>
|
||
|
|
+
|
||
|
|
+#include <setjmp.h>
|
||
|
|
+#include <stdbool.h>
|
||
|
|
+#include <sys/syscall.h>
|
||
|
|
+#include <tls.h>
|
||
|
|
+#include <stackinfo.h>
|
||
|
|
+#include <atomic.h>
|
||
|
|
+#include <errno.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
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+/* 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 <pthread.h> 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#ifndef _PTHREAD_H
|
||
|
|
+#define _PTHREAD_H 1
|
||
|
|
+
|
||
|
|
+#include "bits/pthreadtypes_2_17.h"
|
||
|
|
+
|
||
|
|
+#include <features.h>
|
||
|
|
+#include <endian.h>
|
||
|
|
+#include <sched.h>
|
||
|
|
+#include <time.h>
|
||
|
|
+
|
||
|
|
+#include <bits/setjmp.h>
|
||
|
|
+#include <bits/wordsize.h>
|
||
|
|
+#include <bits/types/struct_timespec.h>
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+/* 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 <schwidefsky@de.ibm.com>, 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include "kernel-features_2_17.h"
|
||
|
|
+#include "pthread_2_17.h"
|
||
|
|
+#include "pthreadP_2_17.h"
|
||
|
|
+#include <lowlevellock_2_17.h>
|
||
|
|
+
|
||
|
|
+#include <endian.h>
|
||
|
|
+#include <errno.h>
|
||
|
|
+#include <stap-probe.h>
|
||
|
|
+#include <atomic.h>
|
||
|
|
+
|
||
|
|
+#include <shlib-compat.h>
|
||
|
|
+
|
||
|
|
+/* 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 <drepper@redhat.com>, 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include "pthreadP_2_17.h"
|
||
|
|
+#include <errno.h>
|
||
|
|
+#include <shlib-compat.h>
|
||
|
|
+#include <stap-probe.h>
|
||
|
|
+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 <drepper@redhat.com>, 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include "pthreadP_2_17.h"
|
||
|
|
+#include <shlib-compat.h>
|
||
|
|
+#include <stap-probe.h>
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+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 <schwidefsky@de.ibm.com>, 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include "kernel-features_2_17.h"
|
||
|
|
+#include "pthread_2_17.h"
|
||
|
|
+#include "pthreadP_2_17.h"
|
||
|
|
+#include <lowlevellock_2_17.h>
|
||
|
|
+
|
||
|
|
+#include <endian.h>
|
||
|
|
+#include <errno.h>
|
||
|
|
+
|
||
|
|
+#include <shlib-compat.h>
|
||
|
|
+#include <stap-probe.h>
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+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 <schwidefsky@de.ibm.com>, 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include "kernel-features_2_17.h"
|
||
|
|
+#include "bits/thread-shared-types_2_17.h"
|
||
|
|
+#include <sysdep_2_17.h>
|
||
|
|
+#include "pthread_2_17.h"
|
||
|
|
+#include "pthreadP_2_17.h"
|
||
|
|
+
|
||
|
|
+#include <endian.h>
|
||
|
|
+#include <errno.h>
|
||
|
|
+#include <lowlevellock_2_17.h>
|
||
|
|
+#include <sys/time.h>
|
||
|
|
+
|
||
|
|
+#include <shlib-compat.h>
|
||
|
|
+
|
||
|
|
+# 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 <schwidefsky@de.ibm.com>, 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include "bits/thread-shared-types_2_17.h"
|
||
|
|
+#include <sysdep_2_17.h>
|
||
|
|
+#include <lowlevellock_2_17.h>
|
||
|
|
+#include "kernel-features_2_17.h"
|
||
|
|
+#include "pthread_2_17.h"
|
||
|
|
+#include "pthreadP_2_17.h"
|
||
|
|
+
|
||
|
|
+#include <endian.h>
|
||
|
|
+#include <errno.h>
|
||
|
|
+
|
||
|
|
+#include <shlib-compat.h>
|
||
|
|
+#include <stap-probe.h>
|
||
|
|
+
|
||
|
|
+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 <drepper@redhat.com>, 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#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 <drepper@redhat.com>, 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#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 <drepper@redhat.com>, 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include "pthreadP_2_17.h"
|
||
|
|
+#include <string.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..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 <drepper@redhat.com>, 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include "pthreadP_2_17.h"
|
||
|
|
+#include <assert.h>
|
||
|
|
+#include <errno.h>
|
||
|
|
+#include <stdbool.h>
|
||
|
|
+#include <time.h>
|
||
|
|
+#include <sysdep.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..674ae77b
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/nptl_2_17/pthread_mutex_cond_lock_2_17.c
|
||
|
|
@@ -0,0 +1,21 @@
|
||
|
|
+#include <pthreadP_2_17.h>
|
||
|
|
+
|
||
|
|
+#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 <pthread_mutex_lock_2_17.c>
|
||
|
|
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 <drepper@redhat.com>, 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include "pthreadP_2_17.h"
|
||
|
|
+#include <assert.h>
|
||
|
|
+#include <errno.h>
|
||
|
|
+#include <stdlib.h>
|
||
|
|
+#include <unistd.h>
|
||
|
|
+#include <sys/param.h>
|
||
|
|
+#include <not-cancel_2_17.h>
|
||
|
|
+#include <atomic.h>
|
||
|
|
+#include <lowlevellock_2_17.h>
|
||
|
|
+#include <stap-probe.h>
|
||
|
|
+
|
||
|
|
+#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 <drepper@redhat.com>, 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include "pthreadP_2_17.h"
|
||
|
|
+#include <lowlevellock_2_17.h>
|
||
|
|
+#include <assert.h>
|
||
|
|
+#include <errno.h>
|
||
|
|
+#include <stdlib.h>
|
||
|
|
+#include <stap-probe.h>
|
||
|
|
+
|
||
|
|
+#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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#ifndef _BITS_PTHREADTYPES_ARCH_H
|
||
|
|
+#define _BITS_PTHREADTYPES_ARCH_H 1
|
||
|
|
+
|
||
|
|
+#include <endian.h>
|
||
|
|
+
|
||
|
|
+#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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#ifndef STUB_FUTEX_INTERNAL_H
|
||
|
|
+#define STUB_FUTEX_INTERNAL_H
|
||
|
|
+
|
||
|
|
+#include <sys/time.h>
|
||
|
|
+#include <stdio.h>
|
||
|
|
+#include <stdbool.h>
|
||
|
|
+#include <libc-diag.h>
|
||
|
|
+
|
||
|
|
+/* 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 = <get lock associated with futex> (FUTEX_WORD);
|
||
|
|
+ wait_flag = <get wait_flag associated with futex> (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) && !<spurious wake-up>);
|
||
|
|
+
|
||
|
|
+ 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 = <get lock associated with futex> (FUTEX_WORD);
|
||
|
|
+ lock (l);
|
||
|
|
+ for (res = 0; PROCESSES_TO_WAKE > 0; PROCESSES_TO_WAKE--, res++) {
|
||
|
|
+ if (<no process blocked on futex>) break;
|
||
|
|
+ wf = <get wait_flag of a process blocked on futex> (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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#ifndef _LOWLEVELLOCK_H
|
||
|
|
+#define _LOWLEVELLOCK_H 1
|
||
|
|
+
|
||
|
|
+#include <atomic.h>
|
||
|
|
+#include <lowlevellock-futex_2_17.h>
|
||
|
|
+
|
||
|
|
+/* 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include <sysdeps/generic/sysdep_2_17.h>
|
||
|
|
+
|
||
|
|
+#include <sys/syscall.h>
|
||
|
|
+#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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#ifndef _LINUX_AARCH64_SYSDEP_H
|
||
|
|
+#define _LINUX_AARCH64_SYSDEP_H 1
|
||
|
|
+
|
||
|
|
+#include <descr_2_17.h>
|
||
|
|
+#include <lowlevellock-futex_2_17.h>
|
||
|
|
+#include <sysdeps/unix/sysdep_2_17.h>
|
||
|
|
+#include <sysdeps/aarch64/sysdep.h>
|
||
|
|
+#include <sysdeps/unix/sysv/linux/generic/sysdep_2_17.h>
|
||
|
|
+
|
||
|
|
+/* Defines RTLD_PRIVATE_ERRNO and USE_DL_SYSINFO. */
|
||
|
|
+#include <dl-sysdep.h>
|
||
|
|
+
|
||
|
|
+#include <tls.h>
|
||
|
|
+
|
||
|
|
+/* In order to get __set_errno() definition in INLINE_SYSCALL. */
|
||
|
|
+#ifndef __ASSEMBLER__
|
||
|
|
+#include <errno.h>
|
||
|
|
+#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 <cmetcalf@tilera.com>, 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include <bits/wordsize.h>
|
||
|
|
+#include <kernel-features.h>
|
||
|
|
+#include <sysdeps/unix/sysdep_2_17.h>
|
||
|
|
+#include <sysdeps/unix/sysv/linux/sysdep_2_17.h>
|
||
|
|
+
|
||
|
|
+/* 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#ifndef __INTERNAL_SIGNALS_H
|
||
|
|
+# define __INTERNAL_SIGNALS_H
|
||
|
|
+
|
||
|
|
+#include <sysdep_2_17.h>
|
||
|
|
+#include <signal.h>
|
||
|
|
+#include <sigsetops.h>
|
||
|
|
+#include <stdbool.h>
|
||
|
|
+
|
||
|
|
+/* 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#ifndef _LOWLEVELLOCK_FUTEX_H
|
||
|
|
+#define _LOWLEVELLOCK_FUTEX_H 1
|
||
|
|
+
|
||
|
|
+#ifndef __ASSEMBLER__
|
||
|
|
+#include <sysdep_2_17.h>
|
||
|
|
+#include <tls.h>
|
||
|
|
+#include <kernel-features.h>
|
||
|
|
+#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 <drepper@redhat.com>, 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#ifndef NOT_CANCEL_H
|
||
|
|
+# define NOT_CANCEL_H
|
||
|
|
+
|
||
|
|
+#include <fcntl.h>
|
||
|
|
+#include <sysdep_2_17.h>
|
||
|
|
+#include <errno.h>
|
||
|
|
+#include <unistd.h>
|
||
|
|
+#include <sys/syscall.h>
|
||
|
|
+#include <sys/wait.h>
|
||
|
|
+#include <time.h>
|
||
|
|
+
|
||
|
|
+/* 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include <bits/wordsize.h>
|
||
|
|
+#include <kernel-features.h>
|
||
|
|
+
|
||
|
|
+/* 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#ifndef _LINUX_X86_64_SYSDEP_H
|
||
|
|
+#define _LINUX_X86_64_SYSDEP_H 1
|
||
|
|
+
|
||
|
|
+/* There is some commonality. */
|
||
|
|
+#include <sysdeps/unix/sysv/linux/sysdep_2_17.h>
|
||
|
|
+#include <sysdeps/unix/x86_64/sysdep_2_17.h>
|
||
|
|
+#include "descr_2_17.h"
|
||
|
|
+#include <tls.h>
|
||
|
|
+
|
||
|
|
+/* Defines RTLD_PRIVATE_ERRNO. */
|
||
|
|
+#include <dl-sysdep.h>
|
||
|
|
+
|
||
|
|
+/* 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include <sysdeps/unix/sysdep_2_17.h>
|
||
|
|
+#include <sysdeps/x86_64/sysdep_2_17.h>
|
||
|
|
+
|
||
|
|
+#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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#ifndef _X86_SYSDEP_H
|
||
|
|
+#define _X86_SYSDEP_H 1
|
||
|
|
+
|
||
|
|
+#include <sysdeps/generic/sysdep_2_17.h>
|
||
|
|
+
|
||
|
|
+/* __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<<log2
|
||
|
|
+#define ASM_SIZE_DIRECTIVE(name) .size name,.-name;
|
||
|
|
+
|
||
|
|
+/* Define an entry point visible from C. */
|
||
|
|
+#define ENTRY(name) \
|
||
|
|
+ .globl C_SYMBOL_NAME(name); \
|
||
|
|
+ .type C_SYMBOL_NAME(name),@function; \
|
||
|
|
+ .align ALIGNARG(4); \
|
||
|
|
+ C_LABEL(name) \
|
||
|
|
+ cfi_startproc; \
|
||
|
|
+ _CET_ENDBR; \
|
||
|
|
+ CALL_MCOUNT
|
||
|
|
+
|
||
|
|
+#undef END
|
||
|
|
+#define END(name) \
|
||
|
|
+ cfi_endproc; \
|
||
|
|
+ ASM_SIZE_DIRECTIVE(name)
|
||
|
|
+
|
||
|
|
+#define ENTRY_CHK(name) ENTRY (name)
|
||
|
|
+#define END_CHK(name) END (name)
|
||
|
|
+
|
||
|
|
+/* Since C identifiers are not normally prefixed with an underscore
|
||
|
|
+ on this system, the asm identifier `syscall_error' intrudes on the
|
||
|
|
+ C name space. Make sure we use an innocuous name. */
|
||
|
|
+#define syscall_error __syscall_error
|
||
|
|
+#define mcount _mcount
|
||
|
|
+
|
||
|
|
+#undef PSEUDO_END
|
||
|
|
+#define PSEUDO_END(name) \
|
||
|
|
+ END (name)
|
||
|
|
+
|
||
|
|
+/* Local label name for asm code. */
|
||
|
|
+#ifndef L
|
||
|
|
+/* ELF-like local names start with `.L'. */
|
||
|
|
+# define L(name) .L##name
|
||
|
|
+#endif
|
||
|
|
+
|
||
|
|
+#define atom_text_section .section ".text.atom", "ax"
|
||
|
|
+
|
||
|
|
+#endif /* __ASSEMBLER__ */
|
||
|
|
+
|
||
|
|
+#endif /* _X86_SYSDEP_H */
|
||
|
|
diff --git a/nptl_2_17/sysdeps/x86_64/nptl/bits/pthreadtypes-arch_2_17.h b/nptl_2_17/sysdeps/x86_64/nptl/bits/pthreadtypes-arch_2_17.h
|
||
|
|
new file mode 100644
|
||
|
|
index 00000000..290f2f46
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/nptl_2_17/sysdeps/x86_64/nptl/bits/pthreadtypes-arch_2_17.h
|
||
|
|
@@ -0,0 +1,106 @@
|
||
|
|
+/* 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#ifndef _BITS_PTHREADTYPES_ARCH_H
|
||
|
|
+#define _BITS_PTHREADTYPES_ARCH_H 1
|
||
|
|
+
|
||
|
|
+#include <bits/wordsize.h>
|
||
|
|
+
|
||
|
|
+#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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#ifndef _X86_64_SYSDEP_H
|
||
|
|
+#define _X86_64_SYSDEP_H 1
|
||
|
|
+
|
||
|
|
+#include <sysdeps/x86/sysdep_2_17.h>
|
||
|
|
+
|
||
|
|
+#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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#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 <pthread.h>
|
||
|
|
+#include <stdint.h>
|
||
|
|
+#include <sys/types.h>
|
||
|
|
+#include <sys/procfs.h>
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+/* 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 <jakub@redhat.com>, 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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include "pthreadP_2_17.h"
|
||
|
|
+#include <assert.h>
|
||
|
|
+#include <atomic.h>
|
||
|
|
+#include <errno.h>
|
||
|
|
+#include <sched.h>
|
||
|
|
+#include <stdlib.h>
|
||
|
|
+#include <atomic.h>
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+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
|
||
|
|
+ <http://www.gnu.org/licenses/>. */
|
||
|
|
+
|
||
|
|
+#include "pthreadP_2_17.h"
|
||
|
|
+#include <stdlib.h>
|
||
|
|
+#include <tls.h>
|
||
|
|
+#include <unistd.h>
|
||
|
|
+
|
||
|
|
+/* 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
|
||
|
|
|