about summary refs log tree commit diff
path: root/sysdeps/unix
diff options
context:
space:
mode:
authorRoland McGrath <roland@hack.frob.com>2014-06-26 09:31:11 -0700
committerRoland McGrath <roland@hack.frob.com>2014-06-26 09:31:11 -0700
commit52ae23b4bfa09fa1f42e3f659aaa057d1176d06b (patch)
tree7c61e56d7fbbb3c9f82994b5d3d778cc19ee48c2 /sysdeps/unix
parent39507e4a6c52d67780d194dae8cfb636e2dbb87e (diff)
downloadglibc-52ae23b4bfa09fa1f42e3f659aaa057d1176d06b.tar.gz
glibc-52ae23b4bfa09fa1f42e3f659aaa057d1176d06b.tar.xz
glibc-52ae23b4bfa09fa1f42e3f659aaa057d1176d06b.zip
Move remaining S390 code out of nptl/.
Diffstat (limited to 'sysdeps/unix')
-rw-r--r--sysdeps/unix/sysv/linux/s390/Makefile13
-rw-r--r--sysdeps/unix/sysv/linux/s390/Versions6
-rw-r--r--sysdeps/unix/sysv/linux/s390/elision-conf.c82
-rw-r--r--sysdeps/unix/sysv/linux/s390/elision-conf.h44
-rw-r--r--sysdeps/unix/sysv/linux/s390/elision-lock.c119
-rw-r--r--sysdeps/unix/sysv/linux/s390/elision-timed.c26
-rw-r--r--sysdeps/unix/sysv/linux/s390/elision-trylock.c94
-rw-r--r--sysdeps/unix/sysv/linux/s390/elision-unlock.c38
-rw-r--r--sysdeps/unix/sysv/linux/s390/force-elision.h33
-rw-r--r--sysdeps/unix/sysv/linux/s390/jmp-unwind.c39
-rw-r--r--sysdeps/unix/sysv/linux/s390/lowlevellock.h390
-rw-r--r--sysdeps/unix/sysv/linux/s390/pt-longjmp.c63
-rw-r--r--sysdeps/unix/sysv/linux/s390/pthread_mutex_cond_lock.c22
-rw-r--r--sysdeps/unix/sysv/linux/s390/pthread_mutex_lock.c22
-rw-r--r--sysdeps/unix/sysv/linux/s390/pthread_mutex_timedlock.c22
-rw-r--r--sysdeps/unix/sysv/linux/s390/pthread_mutex_trylock.c22
-rw-r--r--sysdeps/unix/sysv/linux/s390/pthread_once.c110
-rw-r--r--sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h139
-rw-r--r--sysdeps/unix/sysv/linux/s390/s390-64/Versions8
-rw-r--r--sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h152
-rw-r--r--sysdeps/unix/sysv/linux/s390/s390-64/timer_create.c1
-rw-r--r--sysdeps/unix/sysv/linux/s390/s390-64/timer_delete.c1
-rw-r--r--sysdeps/unix/sysv/linux/s390/s390-64/timer_getoverr.c1
-rw-r--r--sysdeps/unix/sysv/linux/s390/s390-64/timer_gettime.c1
-rw-r--r--sysdeps/unix/sysv/linux/s390/s390-64/timer_settime.c1
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>