diff options
Diffstat (limited to 'sysdeps/unix/sysv/linux')
25 files changed, 1449 insertions, 0 deletions
diff --git a/sysdeps/unix/sysv/linux/s390/Makefile b/sysdeps/unix/sysv/linux/s390/Makefile index f91179d0fc..768f926fb8 100644 --- a/sysdeps/unix/sysv/linux/s390/Makefile +++ b/sysdeps/unix/sysv/linux/s390/Makefile @@ -22,3 +22,16 @@ ifeq (yes,$(build-shared)) sysdep_routines += v1-longjmp_chk endif endif + +ifeq ($(subdir),nptl) +ifeq ($(enable-lock-elision),yes) +libpthread-sysdep_routines += elision-lock elision-unlock elision-timed \ + elision-trylock + +elision-CFLAGS = -mhtm +CFLAGS-elision-lock.c = $(elision-CFLAGS) +CFLAGS-elision-timed.c = $(elision-CFLAGS) +CFLAGS-elision-trylock.c = $(elision-CFLAGS) +CFLAGS-elision-unlock.c = $(elision-CFLAGS) +endif +endif diff --git a/sysdeps/unix/sysv/linux/s390/Versions b/sysdeps/unix/sysv/linux/s390/Versions index f71a6bd2c3..55518a7e5f 100644 --- a/sysdeps/unix/sysv/linux/s390/Versions +++ b/sysdeps/unix/sysv/linux/s390/Versions @@ -8,3 +8,9 @@ libc { __vdso_clock_getres; } } + +libpthread { + GLIBC_2.19 { + longjmp; siglongjmp; + } +} diff --git a/sysdeps/unix/sysv/linux/s390/elision-conf.c b/sysdeps/unix/sysv/linux/s390/elision-conf.c new file mode 100644 index 0000000000..69c04836ed --- /dev/null +++ b/sysdeps/unix/sysv/linux/s390/elision-conf.c @@ -0,0 +1,82 @@ +/* Lock elision tunable parameters. + Copyright (C) 2014 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.h> +#include <elision-conf.h> +#include <unistd.h> +#include <dl-procinfo.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 to not attempt to use elision if a lock used up all retries + without success. Expressed in number of lock acquisition attempts. */ + .skip_lock_out_of_tbegin_retries = 3, + /* How often we try 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. */ + .try_tbegin = 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; + +/* Initialize elison. */ + +static void +elision_init (int argc __attribute__ ((unused)), + char **argv __attribute__ ((unused)), + char **environ) +{ + /* Set when the CPU and the kernel supports transactional execution. + When false elision is never attempted. */ + int elision_available = (GLRO (dl_hwcap) & HWCAP_S390_TE) ? 1 : 0; + + __pthread_force_elision = __libc_enable_secure ? 0 : elision_available; +} + +#ifdef SHARED +# define INIT_SECTION ".init_array" +# define MAYBE_CONST +#else +# define INIT_SECTION ".preinit_array" +# define MAYBE_CONST const +#endif + +void (*MAYBE_CONST __pthread_init_array []) (int, char **, char **) + __attribute__ ((section (INIT_SECTION), aligned (sizeof (void *)))) = +{ + &elision_init +}; diff --git a/sysdeps/unix/sysv/linux/s390/elision-conf.h b/sysdeps/unix/sysv/linux/s390/elision-conf.h new file mode 100644 index 0000000000..d9e97947a0 --- /dev/null +++ b/sysdeps/unix/sysv/linux/s390/elision-conf.h @@ -0,0 +1,44 @@ +/* Lock elision tunable parameters. + Copyright (C) 2014 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/>. */ +#ifdef ENABLE_LOCK_ELISION +#ifndef _ELISION_CONF_H +#define _ELISION_CONF_H 1 + +#include <pthread.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 skip_lock_out_of_tbegin_retries; + int try_tbegin; + 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 +#endif diff --git a/sysdeps/unix/sysv/linux/s390/elision-lock.c b/sysdeps/unix/sysv/linux/s390/elision-lock.c new file mode 100644 index 0000000000..ba5338fbb9 --- /dev/null +++ b/sysdeps/unix/sysv/linux/s390/elision-lock.c @@ -0,0 +1,119 @@ +/* Elided pthread mutex lock. + Copyright (C) 2014 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.h> +#include <pthreadP.h> +#include <lowlevellock.h> +#include <htmintrin.h> +#include <elision-conf.h> +#include <stdint.h> + +#if !defined(LLL_LOCK) && !defined(EXTRAARG) +/* Make sure the configuration code is always linked in for static + libraries. */ +#include "elision-conf.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) +{ + if (*adapt_count > 0) + { + /* Lost updates are possible, but harmless. Due to races this might lead + to *adapt_count becoming less than zero. */ + (*adapt_count)--; + goto use_lock; + } + + __asm__ volatile (".machinemode \"zarch_nohighgprs\"\n\t" + ".machine \"all\"" + : : : "memory"); + + int try_tbegin; + for (try_tbegin = aconf.try_tbegin; + try_tbegin > 0; + try_tbegin--) + { + unsigned status; + if (__builtin_expect + ((status = __builtin_tbegin((void *)0)) == _HTM_TBEGIN_STARTED, 1)) + { + if (*futex == 0) + return 0; + /* Lock was busy. Fall back to normal locking. */ + if (__builtin_expect (__builtin_tx_nesting_depth (), 1)) + { + /* In a non-nested transaction there is no need to abort, + which is expensive. */ + __builtin_tend (); + if (aconf.skip_lock_busy > 0) + *adapt_count = aconf.skip_lock_busy; + goto use_lock; + } + else /* nesting depth is > 1 */ + { + /* A nested transaction will abort eventually because it + cannot make any progress before *futex changes back to 0. + So we may as well abort immediately. + This persistently aborts the outer transaction to force + the outer mutex use the default lock instead of retrying + with transactions until the try_tbegin of the outer mutex + is zero. + The adapt_count of this inner mutex is not changed, + because using the default lock with the inner mutex + would abort the outer transaction. + */ + __builtin_tabort (_HTM_FIRST_USER_ABORT_CODE | 1); + } + } + else + { + if (status != _HTM_TBEGIN_TRANSIENT) + { + /* A persistent abort (cc 1 or 3) indicates that a retry is + probably futile. Use the normal locking now and for the + next couple of calls. + Be careful to avoid writing to the lock. */ + if (aconf.skip_lock_internal_abort > 0) + *adapt_count = aconf.skip_lock_internal_abort; + goto use_lock; + } + } + } + + /* Same logic as above, but for for a number of temporary failures in a + row. */ + if (aconf.skip_lock_out_of_tbegin_retries > 0 && aconf.try_tbegin > 0) + *adapt_count = aconf.skip_lock_out_of_tbegin_retries; + + use_lock: + return LLL_LOCK ((*futex), private); +} diff --git a/sysdeps/unix/sysv/linux/s390/elision-timed.c b/sysdeps/unix/sysv/linux/s390/elision-timed.c new file mode 100644 index 0000000000..a8d8b2a348 --- /dev/null +++ b/sysdeps/unix/sysv/linux/s390/elision-timed.c @@ -0,0 +1,26 @@ +/* Lock elision timed lock. + Copyright (C) 2014 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.h> +#include <lowlevellock.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.c" diff --git a/sysdeps/unix/sysv/linux/s390/elision-trylock.c b/sysdeps/unix/sysv/linux/s390/elision-trylock.c new file mode 100644 index 0000000000..61447d6bf4 --- /dev/null +++ b/sysdeps/unix/sysv/linux/s390/elision-trylock.c @@ -0,0 +1,94 @@ +/* Elided pthread mutex trylock. + Copyright (C) 2014 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.h> +#include <pthreadP.h> +#include <lowlevellock.h> +#include <htmintrin.h> +#include <elision-conf.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) +{ + __asm__ volatile (".machinemode \"zarch_nohighgprs\"\n\t" + ".machine \"all\"" + : : : "memory"); + + /* Implement POSIX semantics by forbiding nesting elided trylocks. + Sorry. After the abort the code is re-executed + non transactional and if the lock was already locked + return an error. */ + if (__builtin_tx_nesting_depth () > 0) + { + /* Note that this abort may terminate an outermost transaction that + was created outside glibc. + This persistently aborts the current transactions to force + them to use the default lock instead of retrying transactions + until their try_tbegin is zero. + */ + __builtin_tabort (_HTM_FIRST_USER_ABORT_CODE | 1); + } + + /* Only try a transaction if it's worth it. */ + if (*adapt_count <= 0) + { + unsigned status; + + if (__builtin_expect + ((status = __builtin_tbegin ((void *)0)) == _HTM_TBEGIN_STARTED, 1)) + { + if (*futex == 0) + return 0; + /* Lock was busy. Fall back to normal locking. */ + /* Since we are in a non-nested transaction there is no need to abort, + which is expensive. */ + __builtin_tend (); + /* Note: Changing the adapt_count here might abort a transaction on a + different cpu, but that could happen anyway when the futex is + acquired, so there's no need to check the nesting depth here. */ + if (aconf.skip_lock_busy > 0) + *adapt_count = aconf.skip_lock_busy; + } + else + { + if (status != _HTM_TBEGIN_TRANSIENT) + { + /* A persistent abort (cc 1 or 3) indicates that a retry is + probably futile. Use the normal locking now and for the + next couple of calls. + Be careful to avoid writing to the lock. */ + if (aconf.skip_trylock_internal_abort > 0) + *adapt_count = aconf.skip_trylock_internal_abort; + } + } + /* Could do some retries here. */ + } + else + { + /* Lost updates are possible, but harmless. Due to races this might lead + to *adapt_count becoming less than zero. */ + (*adapt_count)--; + } + + return lll_trylock (*futex); +} diff --git a/sysdeps/unix/sysv/linux/s390/elision-unlock.c b/sysdeps/unix/sysv/linux/s390/elision-unlock.c new file mode 100644 index 0000000000..9ceae3ee1e --- /dev/null +++ b/sysdeps/unix/sysv/linux/s390/elision-unlock.c @@ -0,0 +1,38 @@ +/* Commit an elided pthread lock. + Copyright (C) 2014 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.h> +#include <lowlevellock.h> + +int +__lll_unlock_elision(int *futex, int private) +{ + /* If the lock is free, we elided the lock earlier. This does not + necessarily mean that we are in a transaction, because the user code may + have closed the transaction, but that is impossible to detect reliably. */ + if (*futex == 0) + { + __asm__ volatile (".machinemode \"zarch_nohighgprs\"\n\t" + ".machine \"all\"" + : : : "memory"); + __builtin_tend(); + } + else + lll_unlock ((*futex), private); + return 0; +} diff --git a/sysdeps/unix/sysv/linux/s390/force-elision.h b/sysdeps/unix/sysv/linux/s390/force-elision.h new file mode 100644 index 0000000000..8fd7684d9a --- /dev/null +++ b/sysdeps/unix/sysv/linux/s390/force-elision.h @@ -0,0 +1,33 @@ +/* Automatic enabling of elision for mutexes + Copyright (C) 2014 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/>. */ + +#ifdef ENABLE_LOCK_ELISION +/* Check for elision on this lock without upgrading. */ +#define DO_ELISION(m) \ + (__pthread_force_elision \ + && (m->__data.__kind & PTHREAD_MUTEX_NO_ELISION_NP) == 0) \ + +/* Automatically enable elision for existing user lock kinds. */ +#define FORCE_ELISION(m, s) \ + if (__pthread_force_elision \ + && (m->__data.__kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \ + { \ + mutex->__data.__kind |= PTHREAD_MUTEX_ELISION_NP; \ + s; \ + } +#endif diff --git a/sysdeps/unix/sysv/linux/s390/jmp-unwind.c b/sysdeps/unix/sysv/linux/s390/jmp-unwind.c new file mode 100644 index 0000000000..f35eab5ac1 --- /dev/null +++ b/sysdeps/unix/sysv/linux/s390/jmp-unwind.c @@ -0,0 +1,39 @@ +/* Clean up stack frames unwound by longjmp. Linux/s390 version. + Copyright (C) 2003-2014 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 <setjmp.h> +#include <stddef.h> +#include <pthreadP.h> + +extern void __pthread_cleanup_upto (__jmp_buf env, char *targetframe); +#pragma weak __pthread_cleanup_upto + + +void +_longjmp_unwind (jmp_buf env, int val) +{ + char local_var; + +#ifdef SHARED + if (__libc_pthread_functions_init) + PTHFCT_CALL (ptr___pthread_cleanup_upto, (env->__jmpbuf, &local_var)); +#else + if (__pthread_cleanup_upto != NULL) + __pthread_cleanup_upto (env->__jmpbuf, &local_var); +#endif +} diff --git a/sysdeps/unix/sysv/linux/s390/lowlevellock.h b/sysdeps/unix/sysv/linux/s390/lowlevellock.h new file mode 100644 index 0000000000..cabff30be9 --- /dev/null +++ b/sysdeps/unix/sysv/linux/s390/lowlevellock.h @@ -0,0 +1,390 @@ +/* Copyright (C) 2003-2014 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/>. */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H 1 + +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> +#include <atomic.h> +#include <kernel-features.h> + +#define SYS_futex 238 +#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 + + +#if !defined NOT_IN_libc || defined IS_IN_rtld +/* In libc.so or ld.so all futexes are private. */ +# ifdef __ASSUME_PRIVATE_FUTEX +# define __lll_private_flag(fl, private) \ + ((fl) | FUTEX_PRIVATE_FLAG) +# else +# define __lll_private_flag(fl, private) \ + ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex)) +# endif +#else +# ifdef __ASSUME_PRIVATE_FUTEX +# define __lll_private_flag(fl, private) \ + (((fl) | FUTEX_PRIVATE_FLAG) ^ (private)) +# else +# define __lll_private_flag(fl, private) \ + (__builtin_constant_p (private) \ + ? ((private) == 0 \ + ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex)) \ + : (fl)) \ + : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG) \ + & THREAD_GETMEM (THREAD_SELF, header.private_futex)))) +# endif +#endif + +#define lll_futex_wait(futex, val, private) \ + lll_futex_timed_wait (futex, val, NULL, private) + +#define lll_futex_timed_wait(futexp, val, timespec, private) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + \ + INTERNAL_SYSCALL (futex, __err, 4, (futexp), \ + __lll_private_flag (FUTEX_WAIT, private), \ + (val), (timespec)); \ + }) + +#define lll_futex_timed_wait_bitset(futexp, val, timespec, clockbit, private) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + int __op = FUTEX_WAIT_BITSET | clockbit; \ + \ + INTERNAL_SYSCALL (futex, __err, 6, (futexp), \ + __lll_private_flag (__op, private), \ + (val), (timespec), NULL /* Unused. */, \ + FUTEX_BITSET_MATCH_ANY); \ + }) + +#define lll_futex_wake(futexp, nr, private) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + \ + INTERNAL_SYSCALL (futex, __err, 4, (futexp), \ + __lll_private_flag (FUTEX_WAKE, private), \ + (nr), 0); \ + }) + +#define lll_robust_dead(futexv, private) \ + do \ + { \ + int *__futexp = &(futexv); \ + \ + atomic_or (__futexp, FUTEX_OWNER_DIED); \ + lll_futex_wake (__futexp, 1, private); \ + } \ + while (0) + + +/* Returns non-zero if error happened, zero if success. */ +#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val, private) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + \ + __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \ + __lll_private_flag (FUTEX_CMP_REQUEUE, private),\ + (nr_wake), (nr_move), (mutex), (val)); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err); \ + }) + +/* Returns non-zero if error happened, zero if success. */ +#define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + \ + __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \ + __lll_private_flag (FUTEX_WAKE_OP, private), \ + (nr_wake), (nr_wake2), (futexp2), \ + FUTEX_OP_CLEAR_WAKE_IF_GT_ONE); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err); \ + }) + +/* 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, timespec, clockbit, \ + mutex, private) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + int __op = FUTEX_WAIT_REQUEUE_PI | clockbit; \ + \ + INTERNAL_SYSCALL (futex, __err, 5, (futexp), \ + __lll_private_flag (__op, private), \ + (val), (timespec), mutex); \ + }) + +#define lll_futex_cmp_requeue_pi(futexp, nr_wake, nr_move, mutex, val, priv) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + \ + __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \ + __lll_private_flag (FUTEX_CMP_REQUEUE_PI, priv),\ + (nr_wake), (nr_move), (mutex), (val)); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err); \ + }) + +#define lll_compare_and_swap(futex, oldval, newval, operation) \ + do { \ + __typeof (futex) __futex = (futex); \ + __asm __volatile (" l %1,%0\n" \ + "0: " operation "\n" \ + " cs %1,%2,%0\n" \ + " jl 0b\n" \ + "1:" \ + : "=Q" (*__futex), "=&d" (oldval), "=&d" (newval) \ + : "m" (*__futex) : "cc", "memory" ); \ + } while (0) + + +static inline int +__attribute__ ((always_inline)) +__lll_trylock (int *futex) +{ + unsigned int old; + + __asm __volatile ("cs %0,%3,%1" + : "=d" (old), "=Q" (*futex) + : "0" (0), "d" (1), "m" (*futex) : "cc", "memory" ); + return old != 0; +} +#define lll_trylock(futex) __lll_trylock (&(futex)) + + +static inline int +__attribute__ ((always_inline)) +__lll_cond_trylock (int *futex) +{ + unsigned int old; + + __asm __volatile ("cs %0,%3,%1" + : "=d" (old), "=Q" (*futex) + : "0" (0), "d" (2), "m" (*futex) : "cc", "memory" ); + return old != 0; +} +#define lll_cond_trylock(futex) __lll_cond_trylock (&(futex)) + + +static inline int +__attribute__ ((always_inline)) +__lll_robust_trylock (int *futex, int id) +{ + unsigned int old; + + __asm __volatile ("cs %0,%3,%1" + : "=d" (old), "=Q" (*futex) + : "0" (0), "d" (id), "m" (*futex) : "cc", "memory" ); + return old != 0; +} +#define lll_robust_trylock(futex, id) \ + __lll_robust_trylock (&(futex), id) + + +extern void __lll_lock_wait_private (int *futex) attribute_hidden; +extern void __lll_lock_wait (int *futex, int private) attribute_hidden; +extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden; + +static inline void +__attribute__ ((always_inline)) +__lll_lock (int *futex, int private) +{ + 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) + +static inline int +__attribute__ ((always_inline)) +__lll_robust_lock (int *futex, int id, int private) +{ + int result = 0; + if (__builtin_expect (atomic_compare_and_exchange_bool_acq (futex, id, 0), + 0)) + result = __lll_robust_lock_wait (futex, private); + return result; +} +#define lll_robust_lock(futex, id, private) \ + __lll_robust_lock (&(futex), id, private) + +static inline void +__attribute__ ((always_inline)) +__lll_cond_lock (int *futex, int private) +{ + if (__glibc_unlikely (atomic_compare_and_exchange_bool_acq (futex, 2, 0))) + __lll_lock_wait (futex, private); +} +#define lll_cond_lock(futex, private) __lll_cond_lock (&(futex), private) + +#define lll_robust_cond_lock(futex, id, private) \ + __lll_robust_lock (&(futex), (id) | FUTEX_WAITERS, private) + +extern int __lll_timedlock_wait + (int *futex, const struct timespec *, int private) attribute_hidden; +extern int __lll_robust_timedlock_wait + (int *futex, const struct timespec *, int private) attribute_hidden; + +static inline int +__attribute__ ((always_inline)) +__lll_timedlock (int *futex, const struct timespec *abstime, int private) +{ + int result = 0; + if (__glibc_unlikely (atomic_compare_and_exchange_bool_acq (futex, 1, 0))) + result = __lll_timedlock_wait (futex, abstime, private); + return result; +} +#define lll_timedlock(futex, abstime, private) \ + __lll_timedlock (&(futex), abstime, private) + +#ifdef ENABLE_LOCK_ELISION +extern int __lll_timedlock_elision + (int *futex, short *adapt_count, const struct timespec *timeout, int private) + attribute_hidden; + +# define lll_timedlock_elision(futex, adapt_count, timeout, private) \ + __lll_timedlock_elision(&(futex), &(adapt_count), timeout, private) +#endif + +static inline int +__attribute__ ((always_inline)) +__lll_robust_timedlock (int *futex, const struct timespec *abstime, + int id, int private) +{ + int result = 0; + if (__builtin_expect (atomic_compare_and_exchange_bool_acq (futex, id, 0), + 0)) + result = __lll_robust_timedlock_wait (futex, abstime, private); + return result; +} +#define lll_robust_timedlock(futex, abstime, id, private) \ + __lll_robust_timedlock (&(futex), abstime, id, private) + + +#define __lll_unlock(futex, private) \ + (void) \ + ({ int __oldval; \ + int __newval = 0; \ + int *__futexp = (futex); \ + \ + lll_compare_and_swap (__futexp, __oldval, __newval, "slr %2,%2"); \ + if (__glibc_unlikely (__oldval > 1)) \ + lll_futex_wake (__futexp, 1, private); \ + }) +#define lll_unlock(futex, private) __lll_unlock(&(futex), private) + + +#define __lll_robust_unlock(futex, private) \ + (void) \ + ({ int __oldval; \ + int __newval = 0; \ + int *__futexp = (futex); \ + \ + lll_compare_and_swap (__futexp, __oldval, __newval, "slr %2,%2"); \ + if (__glibc_unlikely (__oldval & FUTEX_WAITERS)) \ + lll_futex_wake (__futexp, 1, private); \ + }) +#define lll_robust_unlock(futex, private) \ + __lll_robust_unlock(&(futex), private) + +#define lll_islocked(futex) \ + (futex != 0) + + +/* 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 + wakeup when the clone terminates. The memory location contains the + thread ID while the clone is running and is reset to zero + afterwards. */ +#define __lll_wait_tid(ptid) \ + do \ + { \ + int __tid; \ + \ + while ((__tid = *ptid) != 0) \ + lll_futex_wait (ptid, __tid, LLL_SHARED); \ + } \ + while (0) +#define lll_wait_tid(tid) __lll_wait_tid(&(tid)) + +extern int __lll_timedwait_tid (int *, const struct timespec *) + attribute_hidden; + +#define lll_timedwait_tid(tid, abstime) \ + ({ \ + int __res = 0; \ + if ((tid) != 0) \ + __res = __lll_timedwait_tid (&(tid), (abstime)); \ + __res; \ + }) + +#ifdef ENABLE_LOCK_ELISION +extern int __lll_lock_elision (int *futex, short *adapt_count, int private) + attribute_hidden; + +extern int __lll_unlock_elision(int *futex, int private) + attribute_hidden; + +extern int __lll_trylock_elision(int *futex, short *adapt_count) + attribute_hidden; + +# define lll_lock_elision(futex, adapt_count, private) \ + __lll_lock_elision (&(futex), &(adapt_count), private) +# define lll_unlock_elision(futex, private) \ + __lll_unlock_elision (&(futex), private) +# define lll_trylock_elision(futex, adapt_count) \ + __lll_trylock_elision(&(futex), &(adapt_count)) +#endif + +#endif /* lowlevellock.h */ diff --git a/sysdeps/unix/sysv/linux/s390/pt-longjmp.c b/sysdeps/unix/sysv/linux/s390/pt-longjmp.c new file mode 100644 index 0000000000..801432cccb --- /dev/null +++ b/sysdeps/unix/sysv/linux/s390/pt-longjmp.c @@ -0,0 +1,63 @@ +/* Copyright (C) 2013 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 is a copy of pthread/pt-longjmp.c made for extending the + jmpbuf structure on System z. */ + +#include <setjmp.h> +#include <stdlib.h> +#include <bits/wordsize.h> +#include "pthreadP.h" +#include <shlib-compat.h> +#if defined SHARED && SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_19) + +/* The __v1 version prototypes are declared in v1-setjmp.h which + cannot be included together with setjmp.h. So we put the + prototypes here manually. */ +extern void __v1__libc_siglongjmp (sigjmp_buf env, int val) + __attribute__ ((noreturn)); +extern void __v1__libc_longjmp (sigjmp_buf env, int val) + __attribute__ ((noreturn)); + +void __v1_siglongjmp (sigjmp_buf env, int val) +{ + __v1__libc_siglongjmp (env, val); +} + +void __v1_longjmp (jmp_buf env, int val) +{ + __v1__libc_longjmp (env, val); +} + +compat_symbol (libpthread, __v1_longjmp, longjmp, GLIBC_2_0); +compat_symbol (libpthread, __v1_siglongjmp, siglongjmp, GLIBC_2_0); +#endif /* defined SHARED && SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_19)) */ + +void +__v2_longjmp (jmp_buf env, int val) +{ + __libc_longjmp (env, val); +} + +void +__v2_siglongjmp (jmp_buf env, int val) +{ + __libc_siglongjmp (env, val); +} + +versioned_symbol (libpthread, __v2_longjmp, longjmp, GLIBC_2_19); +versioned_symbol (libpthread, __v2_siglongjmp, siglongjmp, GLIBC_2_19); diff --git a/sysdeps/unix/sysv/linux/s390/pthread_mutex_cond_lock.c b/sysdeps/unix/sysv/linux/s390/pthread_mutex_cond_lock.c new file mode 100644 index 0000000000..6fc0f969ef --- /dev/null +++ b/sysdeps/unix/sysv/linux/s390/pthread_mutex_cond_lock.c @@ -0,0 +1,22 @@ +/* Copyright (C) 2014 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/>. */ + +/* The cond lock is not actually elided yet, but we still need to handle + already elided locks. */ +#include <elision-conf.h> + +#include <nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c> diff --git a/sysdeps/unix/sysv/linux/s390/pthread_mutex_lock.c b/sysdeps/unix/sysv/linux/s390/pthread_mutex_lock.c new file mode 100644 index 0000000000..6fd6a9866f --- /dev/null +++ b/sysdeps/unix/sysv/linux/s390/pthread_mutex_lock.c @@ -0,0 +1,22 @@ +/* Elided version of pthread_mutex_lock. + Copyright (C) 2014 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 <elision-conf.h> +#include <force-elision.h> + +#include <nptl/pthread_mutex_lock.c> diff --git a/sysdeps/unix/sysv/linux/s390/pthread_mutex_timedlock.c b/sysdeps/unix/sysv/linux/s390/pthread_mutex_timedlock.c new file mode 100644 index 0000000000..d0e6537ecc --- /dev/null +++ b/sysdeps/unix/sysv/linux/s390/pthread_mutex_timedlock.c @@ -0,0 +1,22 @@ +/* Elided version of pthread_mutex_timedlock. + Copyright (C) 2014 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 <elision-conf.h> +#include <force-elision.h> + +#include <nptl/pthread_mutex_timedlock.c> diff --git a/sysdeps/unix/sysv/linux/s390/pthread_mutex_trylock.c b/sysdeps/unix/sysv/linux/s390/pthread_mutex_trylock.c new file mode 100644 index 0000000000..ea8a8fff93 --- /dev/null +++ b/sysdeps/unix/sysv/linux/s390/pthread_mutex_trylock.c @@ -0,0 +1,22 @@ +/* Elided version of pthread_mutex_trylock. + Copyright (C) 2014 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 <elision-conf.h> +#include <force-elision.h> + +#include <nptl/pthread_mutex_trylock.c> diff --git a/sysdeps/unix/sysv/linux/s390/pthread_once.c b/sysdeps/unix/sysv/linux/s390/pthread_once.c new file mode 100644 index 0000000000..ce02206c17 --- /dev/null +++ b/sysdeps/unix/sysv/linux/s390/pthread_once.c @@ -0,0 +1,110 @@ +/* Copyright (C) 2003-2014 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 "pthreadP.h" +#include <lowlevellock.h> + + +unsigned long int __fork_generation attribute_hidden; + + +static void +clear_once_control (void *arg) +{ + pthread_once_t *once_control = (pthread_once_t *) arg; + + *once_control = 0; + lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE); +} + + +int +__pthread_once (once_control, init_routine) + pthread_once_t *once_control; + void (*init_routine) (void); +{ + while (1) + { + int oldval; + int newval; + + /* Pseudo code: + oldval = *once_control; + if ((oldval & 2) == 0) + { + newval = (oldval & 3) | __fork_generation | 1; + *once_control = newval; + } + Do this atomically. */ + __asm __volatile (" l %1,%0\n" + "0: lhi %2,2\n" + " tml %1,2\n" + " jnz 1f\n" + " nr %2,%1\n" + " ahi %2,1\n" + " o %2,%3\n" + " cs %1,%2,%0\n" + " jl 0b\n" + "1:" + : "=Q" (*once_control), "=&d" (oldval), "=&d" (newval) + : "m" (__fork_generation), "m" (*once_control) + : "cc" ); + /* Check if the initialized has already been done. */ + if ((oldval & 2) != 0) + break; + /* Check if another thread already runs the initializer. */ + if ((oldval & 1) != 0) + { + /* Check whether the initializer execution was interrupted + by a fork. */ + if (((oldval ^ newval) & -4) == 0) + { + /* Same generation, some other thread was faster. Wait. */ + lll_futex_wait (once_control, newval, LLL_PRIVATE); + continue; + } + } + + /* This thread is the first here. Do the initialization. + Register a cleanup handler so that in case the thread gets + interrupted the initialization can be restarted. */ + pthread_cleanup_push (clear_once_control, once_control); + + init_routine (); + + pthread_cleanup_pop (0); + + + /* Add one to *once_control. */ + __asm __volatile (" l %1,%0\n" + "0: lr %2,%1\n" + " ahi %2,1\n" + " cs %1,%2,%0\n" + " jl 0b\n" + : "=Q" (*once_control), "=&d" (oldval), "=&d" (newval) + : "m" (*once_control) : "cc" ); + + /* Wake up all other threads. */ + lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE); + break; + } + + return 0; +} +weak_alias (__pthread_once, pthread_once) +hidden_def (__pthread_once) diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h b/sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h new file mode 100644 index 0000000000..0eeefca5cb --- /dev/null +++ b/sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h @@ -0,0 +1,139 @@ +/* Copyright (C) 2003-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@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 <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <nptl/pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .text; \ +L(pseudo_cancel): \ + cfi_startproc; \ + STM_##args \ + stm %r12,%r15,48(%r15); \ + cfi_offset (%r15, -36); \ + cfi_offset (%r14, -40); \ + cfi_offset (%r13, -44); \ + cfi_offset (%r12, -48); \ + lr %r14,%r15; \ + ahi %r15,-96; \ + cfi_adjust_cfa_offset (96); \ + st %r14,0(%r15); \ + basr %r13,0; \ +0: l %r1,1f-0b(%r13); \ + bas %r14,0(%r1,%r13); \ + lr %r0,%r2; \ + LM_##args \ + .if SYS_ify (syscall_name) < 256; \ + svc SYS_ify (syscall_name); \ + .else; \ + lhi %r1,SYS_ify (syscall_name); \ + svc 0; \ + .endif; \ + LR7_##args \ + l %r1,2f-0b(%r13); \ + lr %r12,%r2; \ + lr %r2,%r0; \ + bas %r14,0(%r1,%r13); \ + lr %r2,%r12; \ + lm %r12,%r15,48+96(%r15); \ + cfi_endproc; \ + j L(pseudo_check); \ +1: .long CENABLE-0b; \ +2: .long CDISABLE-0b; \ +ENTRY(name) \ + SINGLE_THREAD_P(%r1) \ + jne L(pseudo_cancel); \ +.type __##syscall_name##_nocancel,@function; \ +.globl __##syscall_name##_nocancel; \ +__##syscall_name##_nocancel: \ + DO_CALL(syscall_name, args); \ +L(pseudo_check): \ + lhi %r4,-4095; \ + clr %r2,%r4; \ + jnl SYSCALL_ERROR_LABEL; \ +.size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \ +L(pseudo_end): + +# ifdef IS_IN_libpthread +# define CENABLE __pthread_enable_asynccancel +# define CDISABLE __pthread_disable_asynccancel +# elif !defined NOT_IN_libc +# define CENABLE __libc_enable_asynccancel +# define CDISABLE __libc_disable_asynccancel +# elif defined IS_IN_librt +# define CENABLE __librt_enable_asynccancel +# define CDISABLE __librt_disable_asynccancel +# else +# error Unsupported library +# endif + +#define STM_0 /* Nothing */ +#define STM_1 st %r2,8(%r15); +#define STM_2 stm %r2,%r3,8(%r15); +#define STM_3 stm %r2,%r4,8(%r15); +#define STM_4 stm %r2,%r5,8(%r15); +#define STM_5 stm %r2,%r5,8(%r15); +#define STM_6 stm %r2,%r7,8(%r15); + +#define LM_0 /* Nothing */ +#define LM_1 l %r2,8+96(%r15); +#define LM_2 lm %r2,%r3,8+96(%r15); +#define LM_3 lm %r2,%r4,8+96(%r15); +#define LM_4 lm %r2,%r5,8+96(%r15); +#define LM_5 lm %r2,%r5,8+96(%r15); +#define LM_6 lm %r2,%r5,8+96(%r15); \ + cfi_offset (%r7, -68); \ + l %r7,96+96(%r15); + +#define LR7_0 /* Nothing */ +#define LR7_1 /* Nothing */ +#define LR7_2 /* Nothing */ +#define LR7_3 /* Nothing */ +#define LR7_4 /* Nothing */ +#define LR7_5 /* Nothing */ +#define LR7_6 l %r7,28+96(%r15); \ + cfi_restore (%r7); + +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P(reg) \ + ear reg,%a0; \ + icm reg,15,MULTIPLE_THREADS_OFFSET(reg); +# endif + +#elif !defined __ASSEMBLER__ + +# define SINGLE_THREAD_P (1) +# define NO_CANCELLATION 1 + +#endif + +#ifndef __ASSEMBLER__ +# define RTLD_SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +#endif diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/Versions b/sysdeps/unix/sysv/linux/s390/s390-64/Versions index 83092db48e..3f4d960421 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-64/Versions +++ b/sysdeps/unix/sysv/linux/s390/s390-64/Versions @@ -5,3 +5,11 @@ libc { __frame_state_for; __register_frame_info_table; } } + +librt { + GLIBC_2.3.3 { + # Changed timer_t. + timer_create; timer_delete; timer_getoverrun; timer_gettime; + timer_settime; + } +} diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h b/sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h new file mode 100644 index 0000000000..b3560c8e4e --- /dev/null +++ b/sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h @@ -0,0 +1,152 @@ +/* Copyright (C) 2003-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@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 <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <nptl/pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .text; \ +L(pseudo_cancel): \ + cfi_startproc; \ + STM_##args \ + stmg %r13,%r15,104(%r15); \ + cfi_offset (%r15,-40); \ + cfi_offset (%r14,-48); \ + cfi_offset (%r13,-56); \ + lgr %r14,%r15; \ + aghi %r15,-160; \ + cfi_adjust_cfa_offset (160); \ + stg %r14,0(%r15); \ + brasl %r14,CENABLE; \ + lgr %r0,%r2; \ + LM_##args \ + .if SYS_ify (syscall_name) < 256; \ + svc SYS_ify (syscall_name); \ + .else; \ + lghi %r1,SYS_ify (syscall_name); \ + svc 0; \ + .endif; \ + LR7_##args \ + lgr %r13,%r2; \ + lgr %r2,%r0; \ + brasl %r14,CDISABLE; \ + lgr %r2,%r13; \ + lmg %r13,%r15,104+160(%r15); \ + cfi_endproc; \ + j L(pseudo_check); \ +ENTRY(name) \ + SINGLE_THREAD_P \ + jne L(pseudo_cancel); \ +.type __##syscall_name##_nocancel,@function; \ +.globl __##syscall_name##_nocancel; \ +__##syscall_name##_nocancel: \ + DO_CALL(syscall_name, args); \ +L(pseudo_check): \ + lghi %r4,-4095; \ + clgr %r2,%r4; \ + jgnl SYSCALL_ERROR_LABEL; \ +.size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \ +L(pseudo_end): + +# ifdef IS_IN_libpthread +# define CENABLE __pthread_enable_asynccancel +# define CDISABLE __pthread_disable_asynccancel +# define __local_multiple_threads __pthread_multiple_threads +# elif !defined NOT_IN_libc +# define CENABLE __libc_enable_asynccancel +# define CDISABLE __libc_disable_asynccancel +# define __local_multiple_threads __libc_multiple_threads +# elif defined IS_IN_librt +# define CENABLE __librt_enable_asynccancel +# define CDISABLE __librt_disable_asynccancel +# else +# error Unsupported library +# endif + +#define STM_0 /* Nothing */ +#define STM_1 stg %r2,16(%r15); +#define STM_2 stmg %r2,%r3,16(%r15); +#define STM_3 stmg %r2,%r4,16(%r15); +#define STM_4 stmg %r2,%r5,16(%r15); +#define STM_5 stmg %r2,%r5,16(%r15); +#define STM_6 stmg %r2,%r7,16(%r15); + +#define LM_0 /* Nothing */ +#define LM_1 lg %r2,16+160(%r15); +#define LM_2 lmg %r2,%r3,16+160(%r15); +#define LM_3 lmg %r2,%r4,16+160(%r15); +#define LM_4 lmg %r2,%r5,16+160(%r15); +#define LM_5 lmg %r2,%r5,16+160(%r15); +#define LM_6 lmg %r2,%r5,16+160(%r15); \ + cfi_offset (%r7, -104); \ + lg %r7,160+160(%r15); + +#define LR7_0 /* Nothing */ +#define LR7_1 /* Nothing */ +#define LR7_2 /* Nothing */ +#define LR7_3 /* Nothing */ +#define LR7_4 /* Nothing */ +#define LR7_5 /* Nothing */ +#define LR7_6 lg %r7,56+160(%r15); \ + cfi_restore (%r7); + +# if defined IS_IN_libpthread || !defined NOT_IN_libc +# ifndef __ASSEMBLER__ +extern int __local_multiple_threads attribute_hidden; +# define SINGLE_THREAD_P \ + __builtin_expect (__local_multiple_threads == 0, 1) +# else +# define SINGLE_THREAD_P \ + larl %r1,__local_multiple_threads; \ + icm %r0,15,0(%r1); +# endif + +# else + +# ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +# else +# define SINGLE_THREAD_P \ + ear %r1,%a0; \ + sllg %r1,%r1,32; \ + ear %r1,%a1; \ + icm %r1,15,MULTIPLE_THREADS_OFFSET(%r1); +# endif + +# endif + +#elif !defined __ASSEMBLER__ + +# define SINGLE_THREAD_P (1) +# define NO_CANCELLATION 1 + +#endif + +#ifndef __ASSEMBLER__ +# define RTLD_SINGLE_THREAD_P \ + __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +#endif diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/timer_create.c b/sysdeps/unix/sysv/linux/s390/s390-64/timer_create.c new file mode 100644 index 0000000000..d307135003 --- /dev/null +++ b/sysdeps/unix/sysv/linux/s390/s390-64/timer_create.c @@ -0,0 +1 @@ +#include <sysdeps/unix/sysv/linux/x86_64/timer_create.c> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/timer_delete.c b/sysdeps/unix/sysv/linux/s390/s390-64/timer_delete.c new file mode 100644 index 0000000000..2dd94f5c7a --- /dev/null +++ b/sysdeps/unix/sysv/linux/s390/s390-64/timer_delete.c @@ -0,0 +1 @@ +#include <sysdeps/unix/sysv/linux/x86_64/timer_delete.c> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/timer_getoverr.c b/sysdeps/unix/sysv/linux/s390/s390-64/timer_getoverr.c new file mode 100644 index 0000000000..22eaff5cda --- /dev/null +++ b/sysdeps/unix/sysv/linux/s390/s390-64/timer_getoverr.c @@ -0,0 +1 @@ +#include <sysdeps/unix/sysv/linux/x86_64/timer_getoverr.c> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/timer_gettime.c b/sysdeps/unix/sysv/linux/s390/s390-64/timer_gettime.c new file mode 100644 index 0000000000..cea524bae5 --- /dev/null +++ b/sysdeps/unix/sysv/linux/s390/s390-64/timer_gettime.c @@ -0,0 +1 @@ +#include <sysdeps/unix/sysv/linux/x86_64/timer_gettime.c> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/timer_settime.c b/sysdeps/unix/sysv/linux/s390/s390-64/timer_settime.c new file mode 100644 index 0000000000..fa231149d5 --- /dev/null +++ b/sysdeps/unix/sysv/linux/s390/s390-64/timer_settime.c @@ -0,0 +1 @@ +#include <sysdeps/unix/sysv/linux/x86_64/timer_settime.c> |