mirror of
https://sourceware.org/git/glibc.git
synced 2025-12-24 17:51:17 +03:00
Move remaining S390 code out of nptl/.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -8,3 +8,9 @@ libc {
|
||||
__vdso_clock_getres;
|
||||
}
|
||||
}
|
||||
|
||||
libpthread {
|
||||
GLIBC_2.19 {
|
||||
longjmp; siglongjmp;
|
||||
}
|
||||
}
|
||||
|
||||
82
sysdeps/unix/sysv/linux/s390/elision-conf.c
Normal file
82
sysdeps/unix/sysv/linux/s390/elision-conf.c
Normal file
@@ -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
|
||||
};
|
||||
44
sysdeps/unix/sysv/linux/s390/elision-conf.h
Normal file
44
sysdeps/unix/sysv/linux/s390/elision-conf.h
Normal file
@@ -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
|
||||
119
sysdeps/unix/sysv/linux/s390/elision-lock.c
Normal file
119
sysdeps/unix/sysv/linux/s390/elision-lock.c
Normal file
@@ -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);
|
||||
}
|
||||
26
sysdeps/unix/sysv/linux/s390/elision-timed.c
Normal file
26
sysdeps/unix/sysv/linux/s390/elision-timed.c
Normal file
@@ -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"
|
||||
94
sysdeps/unix/sysv/linux/s390/elision-trylock.c
Normal file
94
sysdeps/unix/sysv/linux/s390/elision-trylock.c
Normal file
@@ -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);
|
||||
}
|
||||
38
sysdeps/unix/sysv/linux/s390/elision-unlock.c
Normal file
38
sysdeps/unix/sysv/linux/s390/elision-unlock.c
Normal file
@@ -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;
|
||||
}
|
||||
33
sysdeps/unix/sysv/linux/s390/force-elision.h
Normal file
33
sysdeps/unix/sysv/linux/s390/force-elision.h
Normal file
@@ -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
|
||||
39
sysdeps/unix/sysv/linux/s390/jmp-unwind.c
Normal file
39
sysdeps/unix/sysv/linux/s390/jmp-unwind.c
Normal file
@@ -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
|
||||
}
|
||||
390
sysdeps/unix/sysv/linux/s390/lowlevellock.h
Normal file
390
sysdeps/unix/sysv/linux/s390/lowlevellock.h
Normal file
@@ -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 */
|
||||
63
sysdeps/unix/sysv/linux/s390/pt-longjmp.c
Normal file
63
sysdeps/unix/sysv/linux/s390/pt-longjmp.c
Normal file
@@ -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);
|
||||
22
sysdeps/unix/sysv/linux/s390/pthread_mutex_cond_lock.c
Normal file
22
sysdeps/unix/sysv/linux/s390/pthread_mutex_cond_lock.c
Normal file
@@ -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>
|
||||
22
sysdeps/unix/sysv/linux/s390/pthread_mutex_lock.c
Normal file
22
sysdeps/unix/sysv/linux/s390/pthread_mutex_lock.c
Normal file
@@ -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>
|
||||
22
sysdeps/unix/sysv/linux/s390/pthread_mutex_timedlock.c
Normal file
22
sysdeps/unix/sysv/linux/s390/pthread_mutex_timedlock.c
Normal file
@@ -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>
|
||||
22
sysdeps/unix/sysv/linux/s390/pthread_mutex_trylock.c
Normal file
22
sysdeps/unix/sysv/linux/s390/pthread_mutex_trylock.c
Normal file
@@ -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>
|
||||
110
sysdeps/unix/sysv/linux/s390/pthread_once.c
Normal file
110
sysdeps/unix/sysv/linux/s390/pthread_once.c
Normal file
@@ -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)
|
||||
139
sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h
Normal file
139
sysdeps/unix/sysv/linux/s390/s390-32/sysdep-cancel.h
Normal file
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
152
sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h
Normal file
152
sysdeps/unix/sysv/linux/s390/s390-64/sysdep-cancel.h
Normal file
@@ -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
|
||||
1
sysdeps/unix/sysv/linux/s390/s390-64/timer_create.c
Normal file
1
sysdeps/unix/sysv/linux/s390/s390-64/timer_create.c
Normal file
@@ -0,0 +1 @@
|
||||
#include <sysdeps/unix/sysv/linux/x86_64/timer_create.c>
|
||||
1
sysdeps/unix/sysv/linux/s390/s390-64/timer_delete.c
Normal file
1
sysdeps/unix/sysv/linux/s390/s390-64/timer_delete.c
Normal file
@@ -0,0 +1 @@
|
||||
#include <sysdeps/unix/sysv/linux/x86_64/timer_delete.c>
|
||||
1
sysdeps/unix/sysv/linux/s390/s390-64/timer_getoverr.c
Normal file
1
sysdeps/unix/sysv/linux/s390/s390-64/timer_getoverr.c
Normal file
@@ -0,0 +1 @@
|
||||
#include <sysdeps/unix/sysv/linux/x86_64/timer_getoverr.c>
|
||||
1
sysdeps/unix/sysv/linux/s390/s390-64/timer_gettime.c
Normal file
1
sysdeps/unix/sysv/linux/s390/s390-64/timer_gettime.c
Normal file
@@ -0,0 +1 @@
|
||||
#include <sysdeps/unix/sysv/linux/x86_64/timer_gettime.c>
|
||||
1
sysdeps/unix/sysv/linux/s390/s390-64/timer_settime.c
Normal file
1
sysdeps/unix/sysv/linux/s390/s390-64/timer_settime.c
Normal file
@@ -0,0 +1 @@
|
||||
#include <sysdeps/unix/sysv/linux/x86_64/timer_settime.c>
|
||||
Reference in New Issue
Block a user