diff options
Diffstat (limited to 'libpthread/nptl/sysdeps/unix')
350 files changed, 31183 insertions, 0 deletions
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile new file mode 100644 index 000000000..34d647527 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../../../ +top_builddir=../../../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.in +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile.in b/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile.in new file mode 100644 index 000000000..ac642f272 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile.in @@ -0,0 +1,256 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_CSRC = pthread_attr_getaffinity.c				\ +		  pthread_attr_setaffinity.c pthread_getaffinity.c	\ +		  pthread_getcpuclockid.c pthread_kill.c		\ +		  pthread_mutex_cond_lock.c pthread_setaffinity.c	\ +		  pthread_yield.c sem_post.c sem_timedwait.c		\ +		  pthread_sigqueue.c 					\ +		  sem_trywait.c sem_wait.c pt-fork.c			\ +		  sigtimedwait.c sigwaitinfo.c sigwait.c pt-sleep.c + +libpthread_SSRC = #ptw-close.S ptw-open.S ptw-waitid.S ptw-waidpid.S ptw-write.S + +libc_CSRC = libc_pthread_init.c libc_multiple_threads.c			\ +	    register-atfork.c unregister-atfork.c getpid.c		\ +	    raise.c sleep.c jmp-unwind.c + +# These provide both a cancellable and a not cancellable implementation +libc_SSRC = close.S open.S write.S read.S waitpid.S + +librt_CSRC := mq_notify.c timer_create.c timer_delete.c			 \ +	      timer_getoverr.c timer_gettime.c timer_routines.c		 \ +	      timer_settime.c + + +ifeq ($(TARGET_ARCH),alpha) +libpthread_CSRC += lowlevellock.c +libc_CSRC += libc-lowlevellock.c +librt_CSRC := mq_notify.c +endif + +ifeq ($(TARGET_ARCH),arm) +libc_SSRC := $(filter-out waitpid.S,$(libc_SSRC)) +libpthread_CSRC += lowlevelrobustlock.c +endif + +ifeq ($(TARGET_ARCH),mips) +libpthread_CSRC += lowlevellock.c lowlevelrobustlock.c +libc_CSRC += libc-lowlevellock.c +endif + +ifeq ($(TARGET_ARCH),powerpc) +libpthread_CSRC += lowlevellock.c +libc_CSRC += libc-lowlevellock.c +librt_CSRC := mq_notify.c +endif + +ifeq ($(TARGET_ARCH),sparc) +libpthread_CSRC += __syscall_error.c lowlevelrobustlock.c +librt_CSRC += __syscall_error.c +endif + +ifeq ($(TARGET_ARCH),sh) +SH_PTHREAD_SPECIFIC := sem_post.c sem_wait.c sem_timedwait.c sem_trywait.c +libpthread_CSRC := $(filter-out $(SH_PTHREAD_SPECIFIC),$(libpthread_CSRC)) +endif + +ifeq ($(TARGET_ARCH),i386) +X86_PTHREAD_SPECIFIC := sem_post.c sem_wait.c sem_timedwait.c sem_trywait.c +libpthread_CSRC := $(filter-out $(X86_PTHREAD_SPECIFIC),$(libpthread_CSRC)) +endif + +ifeq ($(TARGET_ARCH),x86_64) +libc_SSRC := $(filter-out waitpid.S,$(libc_SSRC)) +X64_PTHREAD_SPECIFIC := sem_post.c sem_wait.c sem_timedwait.c sem_trywait.c +libpthread_CSRC := $(filter-out $(X64_PTHREAD_SPECIFIC),$(libpthread_CSRC)) +endif + +CFLAGS-pthread_getcpuclockid.c = -I$(top_srcdir)librt +CFLAGS-pt-pread_pwrite.c = -I$(top_srcdir)libc/sysdeps/linux/$(TARGET_ARCH) \ +			    -I$(top_srcdir)libc/sysdeps/linux/common +CFLAGS-mq_notify.c = -I$(top_srcdir)librt -DIS_IN_librt=1 +CFLAGS-timer_create.c = -I$(top_srcdir)librt -DIS_IN_librt=1 +CFLAGS-timer_delete.c = -I$(top_srcdir)librt -DIS_IN_librt=1 +CFLAGS-timer_getoverr.c = -I$(top_srcdir)librt -DIS_IN_librt=1 +CFLAGS-timer_gettime.c = -I$(top_srcdir)librt -DIS_IN_librt=1 +CFLAGS-timer_routines.c = -I$(top_srcdir)librt -DIS_IN_librt=1 +CFLAGS-timer_settime.c = -I$(top_srcdir)librt -DIS_IN_librt=1 + +CFLAGS-linux = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +CFLAGS-OMIT-libc_pthread_init.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-libc_multiple_threads.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-register-atfork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-unregister-atfork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-getpid.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-raise.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-sleep.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-libc-lowlevellock.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +CFLAGS-OMIT-close.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-open.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-read.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-write.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-waitpid.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +CFLAGS-OMIT-mq_notify.c = -DIS_IN_libpthread=1 +CFLAGS-OMIT-timer_create.c = -DIS_IN_libpthread=1 +CFLAGS-OMIT-timer_delete.c = -DIS_IN_libpthread=1 +CFLAGS-OMIT-timer_getoverr.c = -DIS_IN_libpthread=1 +CFLAGS-OMIT-timer_gettime.c = -DIS_IN_libpthread=1 +CFLAGS-OMIT-timer_routines.c = -DIS_IN_libpthread=1 +CFLAGS-OMIT-timer_settime.c = -DIS_IN_libpthread=1 + +PTHREAD_LINUX_DIR := $(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux +PTHREAD_LINUX_OUT := $(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux + +PTHREAD_LINUX_OBJ := $(patsubst %.c,$(PTHREAD_LINUX_OUT)/%.o,$(libpthread_CSRC)) +PTHREAD_LINUX_OBJ += $(patsubst %.S,$(PTHREAD_LINUX_OUT)/%.o,$(libpthread_SSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(PTHREAD_LINUX_OBJ:.o=.os) +else +libpthread-a-y += $(PTHREAD_LINUX_OBJ) +endif +libpthread-so-y += $(PTHREAD_LINUX_OBJ:.o=.oS) +libpthread-so-y += $(PTHREAD_LINUX_OUT)/pt-raise.oS +libpthread-nomulti-y += $(PTHREAD_LINUX_OBJ) + +ASFLAGS-open.S = -D_LIBC_REENTRANT +ASFLAGS-close.S = -D_LIBC_REENTRANT +ASFLAGS-read.S = -D_LIBC_REENTRANT +ASFLAGS-write.S = -D_LIBC_REENTRANT +ASFLAGS-waitpid.S = -D_LIBC_REENTRANT + +LIBC_LINUX_OBJ := $(patsubst %.c,$(PTHREAD_LINUX_OUT)/%.o,$(libc_CSRC)) +LIBC_LINUX_OBJ += $(patsubst %.S,$(PTHREAD_LINUX_OUT)/%.o,$(libc_SSRC)) + +libc-static-y += $(LIBC_LINUX_OBJ) +libc-shared-y += $(LIBC_LINUX_OBJ:.o=.oS) +libc-nomulti-y += $(LIBC_LINUX_OBJ) + +LIBRT_LINUX_OBJ := $(patsubst %.c,$(PTHREAD_LINUX_OUT)/%.o,$(librt_CSRC)) + +librt-a-y += $(LIBRT_LINUX_OBJ) +librt-so-y += $(LIBRT_LINUX_OBJ:.o=.oS) + +objclean-y += nptl_linux_clean +headers_clean-y += nptl_linux_headers_clean + +# +# Create header files. +# +CFLAGS-gen_lowlevelbarrier.c = -S +CFLAGS-gen_lowlevelcond.c = -S +CFLAGS-gen_lowlevelrwlock.c = -S +CFLAGS-gen_lowlevelrobustlock.c = -S +CFLAGS-gen_lunwindbuf.c = -S +CFLAGS-gen_lstructsem.c = -S +CFLAGS-gen_lpthread-pi-defines.c = -S + +$(PTHREAD_LINUX_OUT)/gen_lowlevelbarrier.c: $(PTHREAD_LINUX_DIR)/lowlevelbarrier.sym +	$(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_LINUX_OUT)/gen_lowlevelcond.c: $(PTHREAD_LINUX_DIR)/lowlevelcond.sym +	$(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_LINUX_OUT)/gen_lowlevelrwlock.c: $(PTHREAD_LINUX_DIR)/lowlevelrwlock.sym +	$(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_LINUX_OUT)/gen_lowlevelrobustlock.c: $(PTHREAD_LINUX_DIR)/lowlevelrobustlock.sym +	$(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_LINUX_OUT)/gen_lunwindbuf.c: $(PTHREAD_LINUX_DIR)/unwindbuf.sym +	$(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_LINUX_OUT)/gen_lstructsem.c: $(PTHREAD_LINUX_DIR)/structsem.sym +	$(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_LINUX_OUT)/gen_lpthread-pi-defines.c: $(PTHREAD_LINUX_DIR)/pthread-pi-defines.sym +	$(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + + +$(PTHREAD_LINUX_OUT)/gen_lowlevelbarrier.s: $(PTHREAD_LINUX_OUT)/gen_lowlevelbarrier.c +	$(compile.c) + +$(PTHREAD_LINUX_OUT)/gen_lowlevelcond.s: $(PTHREAD_LINUX_OUT)/gen_lowlevelcond.c +	$(compile.c) + +$(PTHREAD_LINUX_OUT)/gen_lowlevelrwlock.s: $(PTHREAD_LINUX_OUT)/gen_lowlevelrwlock.c +	$(compile.c) + +$(PTHREAD_LINUX_OUT)/gen_lowlevelrobustlock.s: $(PTHREAD_LINUX_OUT)/gen_lowlevelrobustlock.c +	$(compile.c) + +$(PTHREAD_LINUX_OUT)/gen_lunwindbuf.s: $(PTHREAD_LINUX_OUT)/gen_lunwindbuf.c +	$(compile.c) + +$(PTHREAD_LINUX_OUT)/gen_lstructsem.s: $(PTHREAD_LINUX_OUT)/gen_lstructsem.c +	$(compile.c) + +$(PTHREAD_LINUX_OUT)/gen_lpthread-pi-defines.s: $(PTHREAD_LINUX_OUT)/gen_lpthread-pi-defines.c +	$(compile.c) + + +$(PTHREAD_LINUX_OUT)/lowlevelbarrier.h: $(PTHREAD_LINUX_OUT)/gen_lowlevelbarrier.s +	$(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +$(PTHREAD_LINUX_OUT)/lowlevelcond.h: $(PTHREAD_LINUX_OUT)/gen_lowlevelcond.s +	$(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +$(PTHREAD_LINUX_OUT)/lowlevelrwlock.h: $(PTHREAD_LINUX_OUT)/gen_lowlevelrwlock.s +	$(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +$(PTHREAD_LINUX_OUT)/lowlevelrobustlock.h: $(PTHREAD_LINUX_OUT)/gen_lowlevelrobustlock.s +	$(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +$(PTHREAD_LINUX_OUT)/unwindbuf.h: $(PTHREAD_LINUX_OUT)/gen_lunwindbuf.s +	$(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +$(PTHREAD_LINUX_OUT)/structsem.h: $(PTHREAD_LINUX_OUT)/gen_lstructsem.s +	$(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +$(PTHREAD_LINUX_OUT)/pthread-pi-defines.h: $(PTHREAD_LINUX_OUT)/gen_lpthread-pi-defines.s +	$(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +pregen-headers-$(UCLIBC_HAS_THREADS_NATIVE) += \ +					$(PTHREAD_LINUX_OUT)/lowlevelbarrier.h \ +					$(PTHREAD_LINUX_OUT)/lowlevelcond.h \ +					$(PTHREAD_LINUX_OUT)/lowlevelrwlock.h \ +					$(PTHREAD_LINUX_OUT)/lowlevelrobustlock.h \ +					$(PTHREAD_LINUX_OUT)/unwindbuf.h \ +					$(PTHREAD_LINUX_OUT)/structsem.h \ +					$(PTHREAD_LINUX_OUT)/pthread-pi-defines.h + +HEADERS_BITS_PTHREAD     := $(notdir $(wildcard $(PTHREAD_LINUX_DIR)/bits/*.h)) +ALL_HEADERS_BITS_PTHREAD := $(addprefix include/bits/,$(HEADERS_BITS_PTHREAD)) + +$(ALL_HEADERS_BITS_PTHREAD): +	$(do_ln) ../../$(PTHREAD_LINUX_DIR)/bits/$(@F) $(top_builddir)$@ + +nptl_linux_headers_clean: +	$(do_rm) $(addprefix $(PTHREAD_LINUX_OUT)/gen_lowlevelbarrier., c s) \ +	$(addprefix $(PTHREAD_LINUX_OUT)/gen_lowlevelcond., c s) \ +	$(addprefix $(PTHREAD_LINUX_OUT)/gen_lowlevelrwlock., c s) \ +	$(addprefix $(PTHREAD_LINUX_OUT)/gen_lowlevelrobustlock., c s) \ +	$(addprefix $(PTHREAD_LINUX_OUT)/gen_lunwindbuf., c s) \ +	$(addprefix $(PTHREAD_LINUX_OUT)/gen_lstructsem., c s) \ +	$(addprefix $(PTHREAD_LINUX_OUT)/gen_lpthread-pi-defines., c s) \ +	$(PTHREAD_LINUX_OUT)/lowlevelbarrier.h \ +	$(PTHREAD_LINUX_OUT)/lowlevelcond.h \ +	$(PTHREAD_LINUX_OUT)/lowlevelrwlock.h \ +	$(PTHREAD_LINUX_OUT)/lowlevelrobustlock.h \ +	$(PTHREAD_LINUX_OUT)/unwindbuf.h \ +	$(PTHREAD_LINUX_OUT)/structsem.h \ +	$(PTHREAD_LINUX_OUT)/pthread-pi-defines.h + + +nptl_linux_clean: +	$(do_rm) $(addprefix $(PTHREAD_LINUX_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/__syscall_error.c b/libpthread/nptl/sysdeps/unix/sysv/linux/__syscall_error.c new file mode 100644 index 000000000..5e109a83b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/__syscall_error.c @@ -0,0 +1,18 @@ +/* Wrapper for setting errno. + * + * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org> + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include <errno.h> +#include <features.h> + +/* This routine is jumped to by all the syscall handlers, to stash + * an error number into errno.  */ +int __syscall_error(int err_no) attribute_hidden; +int __syscall_error(int err_no) +{ +	__set_errno(err_no); +	return -1; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/accept.S b/libpthread/nptl/sysdeps/unix/sysv/linux/accept.S new file mode 100644 index 000000000..529763d80 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/accept.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_accept +#error Missing definition of NR_accept needed for cancellation. +#endif +PSEUDO (__libc_accept, accept, 3) +ret +PSEUDO_END(__libc_accept) +libc_hidden_def (__libc_accept) +weak_alias (__libc_accept, __accept) +libc_hidden_weak (__accept) +weak_alias (__libc_accept, accept) +libc_hidden_weak (accept) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/Makefile new file mode 100644 index 000000000..8c8084079 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/Makefile @@ -0,0 +1,2 @@ +# pull in __syscall_error routine, __sigprocmask, __syscall_rt_sigaction +libpthread-routines += ptw-sysdep ptw-sigprocmask ptw-rt_sigaction diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h new file mode 100644 index 000000000..a7c9740a0 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h @@ -0,0 +1,100 @@ +/* Minimum guaranteed maximum values for system limits.  Linux/Alpha version. +   Copyright (C) 1993-1998,2000,2002-2004,2008 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 Library General Public License as +   published by the Free Software Foundation; either version 2 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 +   Library General Public License for more details. + +   You should have received a copy of the GNU Library General Public +   License along with the GNU C Library; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +/* The kernel header pollutes the namespace with the NR_OPEN symbol +   and defines LINK_MAX although filesystems have different maxima.  A +   similar thing is true for OPEN_MAX: the limit can be changed at +   runtime and therefore the macro must not be defined.  Remove this +   after including the header if necessary.  */ +#ifndef NR_OPEN +# define __undef_NR_OPEN +#endif +#ifndef LINK_MAX +# define __undef_LINK_MAX +#endif +#ifndef OPEN_MAX +# define __undef_OPEN_MAX +#endif +#ifndef ARG_MAX +# define __undef_ARG_MAX +#endif + +/* The kernel sources contain a file with all the needed information.  */ +#include <linux/limits.h> + +/* Have to remove NR_OPEN?  */ +#ifdef __undef_NR_OPEN +# undef NR_OPEN +# undef __undef_NR_OPEN +#endif +/* Have to remove LINK_MAX?  */ +#ifdef __undef_LINK_MAX +# undef LINK_MAX +# undef __undef_LINK_MAX +#endif +/* Have to remove OPEN_MAX?  */ +#ifdef __undef_OPEN_MAX +# undef OPEN_MAX +# undef __undef_OPEN_MAX +#endif +/* Have to remove ARG_MAX?  */ +#ifdef __undef_ARG_MAX +# undef ARG_MAX +# undef __undef_ARG_MAX +#endif + +/* The number of data keys per process.  */ +#define _POSIX_THREAD_KEYS_MAX	128 +/* This is the value this implementation supports.  */ +#define PTHREAD_KEYS_MAX	1024 + +/* Controlling the iterations of destructors for thread-specific data.  */ +#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS	4 +/* Number of iterations this implementation does.  */ +#define PTHREAD_DESTRUCTOR_ITERATIONS	_POSIX_THREAD_DESTRUCTOR_ITERATIONS + +/* The number of threads per process.  */ +#define _POSIX_THREAD_THREADS_MAX	64 +/* We have no predefined limit on the number of threads.  */ +#undef PTHREAD_THREADS_MAX + +/* Maximum amount by which a process can descrease its asynchronous I/O +   priority level.  */ +#define AIO_PRIO_DELTA_MAX	20 + +/* Minimum size for a thread.  We are free to choose a reasonable value.  */ +#define PTHREAD_STACK_MIN	24576 + +/* Maximum number of timer expiration overruns.  */ +#define DELAYTIMER_MAX	2147483647 + +/* Maximum tty name length.  */ +#define TTY_NAME_MAX		32 + +/* Maximum login name length.  This is arbitrary.  */ +#define LOGIN_NAME_MAX		256 + +/* Maximum host name length.  */ +#define HOST_NAME_MAX		64 + +/* Maximum message queue priority level.  */ +#define MQ_PRIO_MAX		32768 + +/* Maximum value the semaphore can have.  */ +#define SEM_VALUE_MAX   (2147483647) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h new file mode 100644 index 000000000..41c0be197 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h @@ -0,0 +1,168 @@ +/* Machine-specific pthread type layouts.  Alpha version. +   Copyright (C) 2003, 2004, 2005, 2006, 2007 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H	1 + +#define __SIZEOF_PTHREAD_ATTR_T		56 +#define __SIZEOF_PTHREAD_MUTEX_T	40 +#define __SIZEOF_PTHREAD_MUTEXATTR_T	4 +#define __SIZEOF_PTHREAD_COND_T		48 +#define __SIZEOF_PTHREAD_CONDATTR_T	4 +#define __SIZEOF_PTHREAD_RWLOCK_T	56 +#define __SIZEOF_PTHREAD_RWLOCKATTR_T	8 +#define __SIZEOF_PTHREAD_BARRIER_T	32 +#define __SIZEOF_PTHREAD_BARRIERATTR_T	4 + + +/* Thread identifiers.  The structure of the attribute type is +   deliberately not exposed.  */ +typedef unsigned long int pthread_t; + + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_ATTR_T]; +  long int __align; +} pthread_attr_t; + + +typedef struct __pthread_internal_list +{ +  struct __pthread_internal_list *__prev; +  struct __pthread_internal_list *__next; +} __pthread_list_t; + + +/* Data structures for mutex handling.  The structure of the attribute +   type is deliberately not exposed.  */ +typedef union +{ +  struct __pthread_mutex_s +  { +    int __lock; +    unsigned int __count; +    int __owner; +    unsigned int __nusers; +    /* KIND must stay at this position in the structure to maintain +       binary compatibility.  */ +    int __kind; +    int __spins; +    __pthread_list_t __list; +#define __PTHREAD_MUTEX_HAVE_PREV	1 +  } __data; +  char __size[__SIZEOF_PTHREAD_MUTEX_T]; +  long int __align; +} pthread_mutex_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; +  int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling.  The structure of +   the attribute type is deliberately not exposed.  */ +typedef union +{ +  struct +  { +    int __lock; +    unsigned int __futex; +    __extension__ unsigned long long int __total_seq; +    __extension__ unsigned long long int __wakeup_seq; +    __extension__ unsigned long long int __woken_seq; +    void *__mutex; +    unsigned int __nwaiters; +    unsigned int __broadcast_seq; +  } __data; +  char __size[__SIZEOF_PTHREAD_COND_T]; +  __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_CONDATTR_T]; +  int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling.  The +   structure of the attribute type is deliberately not exposed.  */ +typedef union +{ +  struct +  { +    int __lock; +    unsigned int __nr_readers; +    unsigned int __readers_wakeup; +    unsigned int __writer_wakeup; +    unsigned int __nr_readers_queued; +    unsigned int __nr_writers_queued; +    int __writer; +    int __shared; +    unsigned long int __pad1; +    unsigned long int __pad2; +    /* FLAGS must stay at this position in the structure to maintain +       binary compatibility.  */ +    unsigned int __flags; +  } __data; +  char __size[__SIZEOF_PTHREAD_RWLOCK_T]; +  long int __align; +} pthread_rwlock_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; +  long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type.  */ +typedef volatile int pthread_spinlock_t; + +/* POSIX barriers data type.  The structure of the type is +   deliberately not exposed.  */ +typedef union +{ +  char __size[__SIZEOF_PTHREAD_BARRIER_T]; +  long int __align; +} pthread_barrier_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; +  int __align; +} pthread_barrierattr_t; +#endif + + +#endif	/* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/semaphore.h new file mode 100644 index 000000000..be4469c69 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/semaphore.h @@ -0,0 +1,34 @@ +/* Machine-specific POSIX semaphore type layouts.  Alpha version. +   Copyright (C) 2003 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + +# define __SIZEOF_SEM_T	32 + +/* Value returned if `sem_open' failed.  */ +#define SEM_FAILED      ((sem_t *) 0) + + +typedef union +{ +  char __size[__SIZEOF_SEM_T]; +  long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/clone.S new file mode 100644 index 000000000..eea1cbeed --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/clone.S @@ -0,0 +1,2 @@ +#define RESET_PID +#include <sysdeps/unix/sysv/linux/alpha/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/createthread.c new file mode 100644 index 000000000..6a51e73da --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/createthread.c @@ -0,0 +1,23 @@ +/* Copyright (C) 2003 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +/* Value passed to 'clone' for initialization of the thread register.  */ +#define TLS_VALUE (pd + 1) + +/* Get the real implementation.	 */ +#include <nptl/sysdeps/pthread/createthread.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/fork.c new file mode 100644 index 000000000..ca85fc008 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/fork.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2003 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sched.h> +#include <signal.h> +#include <sysdep.h> +#include <tls.h> + + +#define ARCH_FORK()							\ +  INLINE_SYSCALL (clone, 5,						\ +		  CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD,	\ +		  NULL, NULL, &THREAD_SELF->tid, NULL) + +#include "../fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/lowlevellock.h new file mode 100644 index 000000000..b7f4de338 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/lowlevellock.h @@ -0,0 +1,284 @@ +/* Copyright (C) 2003, 2004, 2006, 2007 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 Libr	\ary; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H	1 + +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> +#include <atomic.h> +#include <sysdep.h> +#include <bits/kernel-features.h> + + +#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_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(futexp, val, private) \ +  lll_futex_timed_wait (futexp, val, NULL, private) + +#define lll_futex_timed_wait(futexp, val, timespec, private) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),		      \ +			      __lll_private_flag (FUTEX_WAIT, private),	      \ +			      (val), (timespec));			      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err)? -__ret : __ret;		      \ +  }) + +#define lll_futex_wake(futexp, nr, private) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),		      \ +			      __lll_private_flag (FUTEX_WAKE, private),	      \ +			      (nr), 0);					      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err)? -__ret : __ret;		      \ +  }) + +#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);				      \ +  }) + + + + +static inline int __attribute__((always_inline)) +__lll_trylock(int *futex) +{ +  return atomic_compare_and_exchange_val_acq (futex, 1, 0) != 0; +} +#define lll_trylock(lock)	__lll_trylock (&(lock)) + + +static inline int __attribute__((always_inline)) +__lll_cond_trylock(int *futex) +{ +  return atomic_compare_and_exchange_val_acq (futex, 2, 0) != 0; +} +#define lll_cond_trylock(lock)	__lll_cond_trylock (&(lock)) + + +static inline int __attribute__((always_inline)) +__lll_robust_trylock(int *futex, int id) +{ +  return atomic_compare_and_exchange_val_acq (futex, id, 0) != 0; +} +#define lll_robust_trylock(lock, id) \ +  __lll_robust_trylock (&(lock), 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 (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 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 (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 (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 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 (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0) +    result = __lll_timedlock_wait (futex, abstime, private); +  return result; +} +#define lll_timedlock(futex, abstime, private) \ +  __lll_timedlock (&(futex), abstime, private) + + +static inline int __attribute__ ((always_inline)) +__lll_robust_timedlock (int *futex, const struct timespec *abstime, +			int id, int private) +{ +  int result = 0; +  if (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 *__futex = (futex);					\ +       int __oldval = atomic_exchange_rel (__futex, 0);		\ +       if (__builtin_expect (__oldval > 1, 0))			\ +	 lll_futex_wake (__futex, 1, private);			\ +    }) +#define lll_unlock(futex, private) __lll_unlock(&(futex), private) + + +#define __lll_robust_unlock(futex, private) \ +  (void)							\ +    ({ int *__futex = (futex);					\ +       int __oldval = atomic_exchange_rel (__futex, 0);		\ +       if (__builtin_expect (__oldval & FUTEX_WAITERS, 0))	\ +	 lll_futex_wake (__futex, 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_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(tid) \ +  do {							\ +    __typeof (tid) __tid;				\ +    while ((__tid = (tid)) != 0)			\ +      lll_futex_wait (&(tid), __tid, LLL_SHARED);	\ +  } while (0) + +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;						\ +  }) + +#endif	/* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pt-vfork.S new file mode 100644 index 000000000..ec5d175be --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pt-vfork.S @@ -0,0 +1,43 @@ +/* Copyright (C) 2003, 2004 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <tcb-offsets.h> + +#undef PSEUDO_PREPARE_ARGS +#define PSEUDO_PREPARE_ARGS						\ +	/* Load the current cached pid value across the vfork.  */	\ +	rduniq;								\ +	ldl	a2, PID_OFFSET(v0);					\ +	mov	v0, a1;							\ +	/* Write back its negation, to indicate that the pid value is	\ +	   uninitialized in the the child, and in the window between	\ +	   here and the point at which we restore the value.  */	\ +	negl	a2, t0;							\ +	stl	t0, PID_OFFSET(v0); + +PSEUDO (__vfork, vfork, 0) + +	/* If we're back in the parent, restore the saved pid.  */ +	beq	v0, 1f +	stl	a2, PID_OFFSET(a1) +1:	ret + +PSEUDO_END (__vfork) + +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pthread_once.c new file mode 100644 index 000000000..8adf8b44e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pthread_once.c @@ -0,0 +1,97 @@ +/* Copyright (C) 2003, 2004, 2007 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#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 +attribute_protected +__pthread_once (pthread_once_t *once_control, void (*init_routine) (void)) +{ +  for (;;) +    { +      int oldval; +      int newval; +      int tmp; + +      /* Pseudo code: +	 newval = __fork_generation | 1; +	 oldval = *once_control; +	 if ((oldval & 2) == 0) +	   *once_control = newval; +	 Do this atomically. +      */ +      newval = __fork_generation | 1; +      __asm __volatile ( +		"1:	ldl_l	%0, %2\n" +		"	and	%0, 2, %1\n" +		"	bne	%1, 2f\n" +		"	mov	%3, %1\n" +		"	stl_c	%1, %2\n" +		"	beq	%1, 1b\n" +		"2:	mb" +		: "=&r" (oldval), "=&r" (tmp), "=m" (*once_control) +		: "r" (newval), "m" (*once_control)); + +      /* Check if the initializer has already been done.  */ +      if ((oldval & 2) != 0) +	return 0; + +      /* Check if another thread already runs the initializer.	*/ +      if ((oldval & 1) == 0) +	break; + +      /* Check whether the initializer execution was interrupted by a fork.  */ +      if (oldval != newval) +	break; + +      /* Same generation, some other thread was faster. Wait.  */ +      lll_futex_wait (once_control, oldval, LLL_PRIVATE); +    } + +  /* 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 to take the bottom 2 bits from 01 to 10.  */ +  atomic_increment (once_control); + +  /* Wake up all other threads.  */ +  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE); + +  return 0; +} +weak_alias (__pthread_once, pthread_once) +strong_alias (__pthread_once, __pthread_once_internal) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/sem_post.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/sem_post.c new file mode 100644 index 000000000..27fd817e6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/sem_post.c @@ -0,0 +1,5 @@ +/* ??? This is an ass-backwards way to do this.  We should simply define +   the acquire/release semantics of atomic_exchange_and_add.  And even if +   we don't do this, we should be using atomic_full_barrier or otherwise.  */ +#define __lll_rel_instr  "mb" +#include "../sem_post.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h new file mode 100644 index 000000000..7049b3607 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h @@ -0,0 +1,177 @@ +/* Copyright (C) 2003, 2006 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#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 + +# ifdef PROF +#  define PSEUDO_PROF				\ +	.set noat;				\ +	lda	AT, _mcount;			\ +	jsr	AT, (AT), _mcount;		\ +	.set at +# else +#  define PSEUDO_PROF +# endif + +/* ??? Assumes that nothing comes between PSEUDO and PSEUDO_END +   besides "ret".  */ + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args)			\ +	.globl name;						\ +	.align 4;						\ +	.type name, @function;					\ +	.usepv name, std;					\ +	cfi_startproc;						\ +__LABEL(name)							\ +	ldgp	gp, 0(pv);					\ +	PSEUDO_PROF;						\ +	PSEUDO_PREPARE_ARGS					\ +	SINGLE_THREAD_P(t0);					\ +	bne	t0, $pseudo_cancel;				\ +	lda	v0, SYS_ify(syscall_name);			\ +	call_pal PAL_callsys;					\ +	bne	a3, SYSCALL_ERROR_LABEL;			\ +__LABEL($pseudo_ret)						\ +	.subsection 2;						\ +	cfi_startproc;						\ +__LABEL($pseudo_cancel)						\ +	subq	sp, 64, sp;					\ +	cfi_def_cfa_offset(64);					\ +	stq	ra, 0(sp);					\ +	cfi_offset(ra, -64);					\ +	SAVE_ARGS_##args;					\ +	CENABLE;						\ +	LOAD_ARGS_##args;					\ +	/* Save the CENABLE return value in RA.  That register	\ +	   is preserved across syscall and the real return 	\ +	   address is saved on the stack.  */			\ +	mov	v0, ra;						\ +	lda	v0, SYS_ify(syscall_name);			\ +	call_pal PAL_callsys;					\ +	stq	v0, 8(sp);					\ +	mov	ra, a0;						\ +	bne	a3, $multi_error;				\ +	CDISABLE;						\ +	ldq	ra, 0(sp);					\ +	ldq	v0, 8(sp);					\ +	addq	sp, 64, sp;					\ +	cfi_remember_state;					\ +	cfi_restore(ra);					\ +	cfi_def_cfa_offset(0);					\ +	ret;							\ +	cfi_restore_state;					\ +__LABEL($multi_error)						\ +	CDISABLE;						\ +	ldq	ra, 0(sp);					\ +	ldq	v0, 8(sp);					\ +	addq	sp, 64, sp;					\ +	cfi_restore(ra);					\ +	cfi_def_cfa_offset(0);					\ +__LABEL($syscall_error)						\ +	SYSCALL_ERROR_HANDLER;					\ +	cfi_endproc;						\ +	.previous + +# undef PSEUDO_END +# define PSEUDO_END(sym)					\ +	cfi_endproc;						\ +	.subsection 2;						\ +	.size sym, .-sym + +# define SAVE_ARGS_0	/* Nothing.  */ +# define SAVE_ARGS_1	SAVE_ARGS_0; stq a0, 8(sp) +# define SAVE_ARGS_2	SAVE_ARGS_1; stq a1, 16(sp) +# define SAVE_ARGS_3	SAVE_ARGS_2; stq a2, 24(sp) +# define SAVE_ARGS_4	SAVE_ARGS_3; stq a3, 32(sp) +# define SAVE_ARGS_5	SAVE_ARGS_4; stq a4, 40(sp) +# define SAVE_ARGS_6	SAVE_ARGS_5; stq a5, 48(sp) + +# define LOAD_ARGS_0	/* Nothing.  */ +# define LOAD_ARGS_1	LOAD_ARGS_0; ldq a0, 8(sp) +# define LOAD_ARGS_2	LOAD_ARGS_1; ldq a1, 16(sp) +# define LOAD_ARGS_3	LOAD_ARGS_2; ldq a2, 24(sp) +# define LOAD_ARGS_4	LOAD_ARGS_3; ldq a3, 32(sp) +# define LOAD_ARGS_5	LOAD_ARGS_4; ldq a4, 40(sp) +# define LOAD_ARGS_6	LOAD_ARGS_5; ldq a5, 48(sp) + +# ifdef IS_IN_libpthread +#  define __local_enable_asynccancel	__pthread_enable_asynccancel +#  define __local_disable_asynccancel	__pthread_disable_asynccancel +#  define __local_multiple_threads	__pthread_multiple_threads +# elif !defined NOT_IN_libc +#  define __local_enable_asynccancel	__libc_enable_asynccancel +#  define __local_disable_asynccancel	__libc_disable_asynccancel +#  define __local_multiple_threads	__libc_multiple_threads +# elif defined IS_IN_librt +#  define __local_enable_asynccancel	__librt_enable_asynccancel +#  define __local_disable_asynccancel	__librt_disable_asynccancel +# else +#  error Unsupported library +# endif + +# ifdef __PIC__ +#  define CENABLE	bsr ra, __local_enable_asynccancel !samegp +#  define CDISABLE	bsr ra, __local_disable_asynccancel !samegp +# else +#  define CENABLE	jsr ra, __local_enable_asynccancel; ldgp ra, 0(gp) +#  define CDISABLE	jsr ra, __local_disable_asynccancel; ldgp ra, 0(gp) +# endif + +# 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) +#  elif defined(__PIC__) +#   define SINGLE_THREAD_P(reg)  ldl reg, __local_multiple_threads(gp) !gprel +#  else +#   define SINGLE_THREAD_P(reg)					\ +	ldah	reg, __local_multiple_threads(gp) !gprelhigh;	\ +	ldl	reg, __local_multiple_threads(reg) !gprellow +#  endif +# else +#  ifndef __ASSEMBLER__ +#   define SINGLE_THREAD_P \ +	__builtin_expect (THREAD_GETMEM (THREAD_SELF, \ +				   header.multiple_threads) == 0, 1) +#  else +#   define SINGLE_THREAD_P(reg)					\ +	call_pal PAL_rduniq;					\ +	ldl reg, MULTIPLE_THREADS_OFFSET($0) +#  endif +# endif + +#else + +# 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/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_create.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_create.c new file mode 100644 index 000000000..172223af3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_create.c @@ -0,0 +1 @@ +#include "../x86_64/timer_create.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_delete.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_delete.c new file mode 100644 index 000000000..537516e0a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_delete.c @@ -0,0 +1 @@ +#include "../x86_64/timer_delete.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_getoverr.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_getoverr.c new file mode 100644 index 000000000..3f21a73c9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_getoverr.c @@ -0,0 +1 @@ +#include "../x86_64/timer_getoverr.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_gettime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_gettime.c new file mode 100644 index 000000000..a50143adc --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_gettime.c @@ -0,0 +1 @@ +#include "../x86_64/timer_gettime.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_settime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_settime.c new file mode 100644 index 000000000..37baeffac --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/timer_settime.c @@ -0,0 +1 @@ +#include "../x86_64/timer_settime.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/vfork.S new file mode 100644 index 000000000..f4ed9311b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/vfork.S @@ -0,0 +1,46 @@ +/* Copyright (C) 2004 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <tcb-offsets.h> + +#undef PSEUDO_PREPARE_ARGS +#define PSEUDO_PREPARE_ARGS						\ +	/* Load the current cached pid value across the vfork.  */	\ +	rduniq;								\ +	ldl	a2, PID_OFFSET(v0);					\ +	mov	v0, a1;							\ +	/* If the cached value is initialized (nonzero), then write	\ +	   back its negation, or INT_MIN, to indicate that the pid	\ +	   value is uninitialized in the the child, and in the window	\ +	   between here and the point at which we restore the value.  */ \ +	ldah	t0, -0x8000;						\ +	negl	a2, t1;							\ +	cmovne	a2, t1, t0;						\ +	stl	t0, PID_OFFSET(v0); + +PSEUDO (__vfork, vfork, 0) + +	/* If we're back in the parent, restore the saved pid.  */ +	beq	v0, 1f +	stl	a2, PID_OFFSET(a1) +1:	ret + +PSEUDO_END (__vfork) +libc_hidden_def (__vfork) +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile new file mode 100644 index 000000000..43a6fad84 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../../../../ +top_builddir=../../../../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.arch +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile.arch new file mode 100644 index 000000000..c5852818d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile.arch @@ -0,0 +1,58 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_SSRC = pt-vfork.S +libpthread_CSRC = pthread_once.c lowlevellock.c \ +                  pt-__syscall_rt_sigaction.c pt-__syscall_error.c + +libc_a_CSRC = fork.c lowlevellock.c +libc_a_SSRC = clone.S vfork.S + +ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y) +CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__ +endif +CFLAGS-pthread_once.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-pt-__syscall_rt_sigaction.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-lowlevellock.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-pt-__syscall_error.c =  -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -marm +# We always compile it in arm mode because of SAVE_PID macro +# This macro should be alternatively implemented in THUMB +# assembly. +ASFLAGS-vfork.S = -marm + +CFLAGS += $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/arm +LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/arm + +LINUX_ARCH_OBJ:=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libpthread_SSRC)) +LINUX_ARCH_OBJ+=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(LINUX_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(LINUX_ARCH_OBJ) +endif +libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y+=$(LINUX_ARCH_OBJ) + +LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC)) +LIBC_LINUX_ARCH_OBJ+=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libc_a_SSRC)) + +libc-static-y+=$(LIBC_LINUX_ARCH_OBJ) +libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS) + +libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ) + +objclean-y+=pthread_linux_arch_objclean + +pthread_linux_arch_objclean: +	$(RM) $(LINUX_ARCH_OUT)/*.{o,os,oS} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h new file mode 100644 index 000000000..b0586ea1e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h @@ -0,0 +1,122 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <stdint.h> +#include <sysdep.h> + + +typedef int8_t atomic8_t; +typedef uint8_t uatomic8_t; +typedef int_fast8_t atomic_fast8_t; +typedef uint_fast8_t uatomic_fast8_t; + +typedef int32_t atomic32_t; +typedef uint32_t uatomic32_t; +typedef int_fast32_t atomic_fast32_t; +typedef uint_fast32_t uatomic_fast32_t; + +typedef intptr_t atomicptr_t; +typedef uintptr_t uatomicptr_t; +typedef intmax_t atomic_max_t; +typedef uintmax_t uatomic_max_t; + +void __arm_link_error (void); + +#ifdef __thumb2__ +#define atomic_full_barrier() \ +     __asm__ __volatile__						      \ +	     ("movw\tip, #0x0fa0\n\t"					      \ +	      "movt\tip, #0xffff\n\t"					      \ +	      "blx\tip"							      \ +	      : : : "ip", "lr", "cc", "memory"); +#else +#define atomic_full_barrier() \ +     __asm__ __volatile__						      \ +	     ("mov\tip, #0xffff0fff\n\t"				      \ +	      "mov\tlr, pc\n\t"						      \ +	      "add\tpc, ip, #(0xffff0fa0 - 0xffff0fff)"			      \ +	      : : : "ip", "lr", "cc", "memory"); +#endif + +/* Atomic compare and exchange.  This sequence relies on the kernel to +   provide a compare and exchange operation which is atomic on the +   current architecture, either via cleverness on pre-ARMv6 or via +   ldrex / strex on ARMv6.  */ + +#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \ +  ({ __arm_link_error (); oldval; }) + +#define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \ +  ({ __arm_link_error (); oldval; }) + +/* It doesn't matter what register is used for a_oldval2, but we must +   specify one to work around GCC PR rtl-optimization/21223.  Otherwise +   it may cause a_oldval or a_tmp to be moved to a different register.  */ + +#ifdef __thumb2__ +/* Thumb-2 has ldrex/strex.  However it does not have barrier instructions, +   so we still need to use the kernel helper.  */ +#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \ +  ({ register __typeof (oldval) a_oldval asm ("r0");			      \ +     register __typeof (oldval) a_newval asm ("r1") = (newval);		      \ +     register __typeof (mem) a_ptr asm ("r2") = (mem);			      \ +     register __typeof (oldval) a_tmp asm ("r3");			      \ +     register __typeof (oldval) a_oldval2 asm ("r4") = (oldval);	      \ +     __asm__ __volatile__						      \ +	     ("0:\tldr\t%[tmp],[%[ptr]]\n\t"				      \ +	      "cmp\t%[tmp], %[old2]\n\t"				      \ +	      "bne\t1f\n\t"						      \ +	      "mov\t%[old], %[old2]\n\t"				      \ +	      "movw\t%[tmp], #0x0fc0\n\t"				      \ +	      "movt\t%[tmp], #0xffff\n\t"				      \ +	      "blx\t%[tmp]\n\t"						      \ +	      "bcc\t0b\n\t"						      \ +	      "mov\t%[tmp], %[old2]\n\t"				      \ +	      "1:"							      \ +	      : [old] "=&r" (a_oldval), [tmp] "=&r" (a_tmp)		      \ +	      : [new] "r" (a_newval), [ptr] "r" (a_ptr),		      \ +		[old2] "r" (a_oldval2)					      \ +	      : "ip", "lr", "cc", "memory");				      \ +     a_tmp; }) +#else +#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \ +  ({ register __typeof (oldval) a_oldval asm ("r0");			      \ +     register __typeof (oldval) a_newval asm ("r1") = (newval);		      \ +     register __typeof (mem) a_ptr asm ("r2") = (mem);			      \ +     register __typeof (oldval) a_tmp asm ("r3");			      \ +     register __typeof (oldval) a_oldval2 asm ("r4") = (oldval);	      \ +     __asm__ __volatile__						      \ +	     ("0:\tldr\t%[tmp],[%[ptr]]\n\t"				      \ +	      "cmp\t%[tmp], %[old2]\n\t"				      \ +	      "bne\t1f\n\t"						      \ +	      "mov\t%[old], %[old2]\n\t"				      \ +	      "mov\t%[tmp], #0xffff0fff\n\t"				      \ +	      "mov\tlr, pc\n\t"						      \ +	      "add\tpc, %[tmp], #(0xffff0fc0 - 0xffff0fff)\n\t"		      \ +	      "bcc\t0b\n\t"						      \ +	      "mov\t%[tmp], %[old2]\n\t"				      \ +	      "1:"							      \ +	      : [old] "=&r" (a_oldval), [tmp] "=&r" (a_tmp)		      \ +	      : [new] "r" (a_newval), [ptr] "r" (a_ptr),		      \ +		[old2] "r" (a_oldval2)					      \ +	      : "ip", "lr", "cc", "memory");				      \ +     a_tmp; }) +#endif + +#define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \ +  ({ __arm_link_error (); oldval; }) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/pthreadtypes.h new file mode 100644 index 000000000..e1b115c8c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/pthreadtypes.h @@ -0,0 +1,181 @@ +/* Copyright (C) 2002, 2003, 2004, 2005, 2006 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H	1 + +#include <endian.h> + +#define __SIZEOF_PTHREAD_ATTR_T 36 +#define __SIZEOF_PTHREAD_MUTEX_T 24 +#define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +#define __SIZEOF_PTHREAD_COND_T 48 +#define __SIZEOF_PTHREAD_COND_COMPAT_T 12 +#define __SIZEOF_PTHREAD_CONDATTR_T 4 +#define __SIZEOF_PTHREAD_RWLOCK_T 32 +#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +#define __SIZEOF_PTHREAD_BARRIER_T 20 +#define __SIZEOF_PTHREAD_BARRIERATTR_T 4 + + +/* Thread identifiers.  The structure of the attribute type is not +   exposed on purpose.  */ +typedef unsigned long int pthread_t; + + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_ATTR_T]; +  long int __align; +} pthread_attr_t; + + +typedef struct __pthread_internal_slist +{ +  struct __pthread_internal_slist *__next; +} __pthread_slist_t; + + +/* Data structures for mutex handling.  The structure of the attribute +   type is not exposed on purpose.  */ +typedef union +{ +  struct __pthread_mutex_s +  { +    int __lock; +    unsigned int __count; +    int __owner; +    /* KIND must stay at this position in the structure to maintain +       binary compatibility.  */ +    int __kind; +    unsigned int __nusers; +    __extension__ union +    { +      int __spins; +      __pthread_slist_t __list; +    }; +  } __data; +  char __size[__SIZEOF_PTHREAD_MUTEX_T]; +  long int __align; +} pthread_mutex_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; +  long int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling.  The structure of +   the attribute type is not exposed on purpose.  */ +typedef union +{ +  struct +  { +    int __lock; +    unsigned int __futex; +    __extension__ unsigned long long int __total_seq; +    __extension__ unsigned long long int __wakeup_seq; +    __extension__ unsigned long long int __woken_seq; +    void *__mutex; +    unsigned int __nwaiters; +    unsigned int __broadcast_seq; +  } __data; +  char __size[__SIZEOF_PTHREAD_COND_T]; +  __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_CONDATTR_T]; +  long int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling.  The +   structure of the attribute type is not exposed on purpose.  */ +typedef union +{ +  struct +  { +    int __lock; +    unsigned int __nr_readers; +    unsigned int __readers_wakeup; +    unsigned int __writer_wakeup; +    unsigned int __nr_readers_queued; +    unsigned int __nr_writers_queued; +#if __BYTE_ORDER == __BIG_ENDIAN +    unsigned char __pad1; +    unsigned char __pad2; +    unsigned char __shared; +    /* FLAGS must stay at this position in the structure to maintain +       binary compatibility.  */ +    unsigned char __flags; +#else +    /* FLAGS must stay at this position in the structure to maintain +       binary compatibility.  */ +    unsigned char __flags; +    unsigned char __shared; +    unsigned char __pad1; +    unsigned char __pad2; +#endif +    int __writer; +  } __data; +  char __size[__SIZEOF_PTHREAD_RWLOCK_T]; +  long int __align; +} pthread_rwlock_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; +  long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type.  */ +typedef volatile int pthread_spinlock_t; + + +/* POSIX barriers data type.  The structure of the type is +   deliberately not exposed.  */ +typedef union +{ +  char __size[__SIZEOF_PTHREAD_BARRIER_T]; +  long int __align; +} pthread_barrier_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; +  int __align; +} pthread_barrierattr_t; +#endif + + +#endif	/* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/semaphore.h new file mode 100644 index 000000000..dadfac2af --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/semaphore.h @@ -0,0 +1,35 @@ +/* Copyright (C) 2002, 2005, 2007 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + + +#define __SIZEOF_SEM_T	16 + + +/* Value returned if `sem_open' failed.  */ +#define SEM_FAILED      ((sem_t *) 0) + + +typedef union +{ +  char __size[__SIZEOF_SEM_T]; +  long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/clone.S new file mode 100644 index 000000000..23227eb24 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/clone.S @@ -0,0 +1,3 @@ +#define RESET_PID +#include <tcb-offsets.h> +#include "../../../../../../../libc/sysdeps/linux/arm/clone.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/createthread.c new file mode 100644 index 000000000..2d4355980 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/createthread.c @@ -0,0 +1,23 @@ +/* Copyright (C) 2005 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +/* Value passed to 'clone' for initialization of the thread register.  */ +#define TLS_VALUE (pd + 1) + +/* Get the real implementation.	 */ +#include <sysdeps/pthread/createthread.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/fork.c new file mode 100644 index 000000000..1c8f4c43a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/fork.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Phil Blundell <pb@nexus.co.uk>, 2005 + +   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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sched.h> +#include <signal.h> +#include <sysdep.h> +#include <tls.h> + + +#define ARCH_FORK()							\ +  INLINE_SYSCALL (clone, 5,						\ +		  CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD,	\ +		  NULL, NULL, NULL, &THREAD_SELF->tid) + +#include "../fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.c new file mode 100644 index 000000000..8c8955e05 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.c @@ -0,0 +1,134 @@ +/* low level locking for pthread library.  Generic futex-using version. +   Copyright (C) 2003, 2005, 2007 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <sys/time.h> +#include <tls.h> + +void +__lll_lock_wait_private (int *futex) +{ +  do +    { +      int oldval = atomic_compare_and_exchange_val_acq (futex, 2, 1); +      if (oldval != 0) +	lll_futex_wait (futex, 2, LLL_PRIVATE); +    } +  while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0); +} + + +/* These functions don't get included in libc.so  */ +#ifdef IS_IN_libpthread +void +__lll_lock_wait (int *futex, int private) +{ +  do +    { +      int oldval = atomic_compare_and_exchange_val_acq (futex, 2, 1); +      if (oldval != 0) +	lll_futex_wait (futex, 2, private); +    } +  while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0); +} + + +int +__lll_timedlock_wait (int *futex, const struct timespec *abstime, int private) +{ +  struct timespec rt; + +  /* Reject invalid timeouts.  */ +  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) +    return EINVAL; + +  /* Upgrade the lock.  */ +  if (atomic_exchange_acq (futex, 2) == 0) +    return 0; + +  do +    { +      struct timeval tv; + +      /* Get the current time.  */ +      (void) gettimeofday (&tv, NULL); + +      /* Compute relative timeout.  */ +      rt.tv_sec = abstime->tv_sec - tv.tv_sec; +      rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; +      if (rt.tv_nsec < 0) +	{ +	  rt.tv_nsec += 1000000000; +	  --rt.tv_sec; +	} + +      /* Already timed out?  */ +      if (rt.tv_sec < 0) +	return ETIMEDOUT; + +      // XYZ: Lost the lock to check whether it was private. +      lll_futex_timed_wait (futex, 2, &rt, private); +    } +  while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0); + +  return 0; +} + + +int +__lll_timedwait_tid (int *tidp, const struct timespec *abstime) +{ +  int tid; + +  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) +    return EINVAL; + +  /* Repeat until thread terminated.  */ +  while ((tid = *tidp) != 0) +    { +      struct timeval tv; +      struct timespec rt; + +      /* Get the current time.  */ +      (void) gettimeofday (&tv, NULL); + +      /* Compute relative timeout.  */ +      rt.tv_sec = abstime->tv_sec - tv.tv_sec; +      rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; +      if (rt.tv_nsec < 0) +	{ +	  rt.tv_nsec += 1000000000; +	  --rt.tv_sec; +	} + +      /* Already timed out?  */ +      if (rt.tv_sec < 0) +	return ETIMEDOUT; + +      /* Wait until thread terminates.  */ +      // XYZ: Lost the lock to check whether it was private. +      if (lll_futex_timed_wait (tidp, tid, &rt, LLL_SHARED) == -ETIMEDOUT) +	return ETIMEDOUT; +    } + +  return 0; +} +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.h new file mode 100644 index 000000000..4c7d08c92 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.h @@ -0,0 +1,282 @@ +/* Copyright (C) 2005, 2006, 2007, 2008, 2009 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H	1 + +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> +#include <atomic.h> +#include <sysdep.h> +#include <bits/kernel-features.h> + +#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_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(futexp, val, private) \ +  lll_futex_timed_wait(futexp, val, NULL, private) + +#define lll_futex_timed_wait(futexp, val, timespec, private) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),		      \ +			      __lll_private_flag (FUTEX_WAIT, private),	      \ +			      (val), (timespec));			      \ +    __ret;								      \ +  }) + +#define lll_futex_wake(futexp, nr, private) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),		      \ +			      __lll_private_flag (FUTEX_WAKE, private),	      \ +			      (nr), 0);					      \ +    __ret;								      \ +  }) + +#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);				      \ +  }) + + +#define lll_trylock(lock)	\ +  atomic_compare_and_exchange_val_acq(&(lock), 1, 0) + +#define lll_cond_trylock(lock)	\ +  atomic_compare_and_exchange_val_acq(&(lock), 2, 0) + +#define __lll_robust_trylock(futex, id) \ +  (atomic_compare_and_exchange_val_acq (futex, id, 0) != 0) +#define lll_robust_trylock(lock, id) \ +  __lll_robust_trylock (&(lock), 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; + +#define __lll_lock(futex, private)					      \ +  ((void) ({								      \ +    int *__futex = (futex);						      \ +    if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex,       \ +								1, 0), 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) + + +#define __lll_robust_lock(futex, id, private)				      \ +  ({									      \ +    int *__futex = (futex);						      \ +    int __val = 0;							      \ +									      \ +    if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \ +								0), 0))	      \ +      __val = __lll_robust_lock_wait (__futex, private);		      \ +    __val;								      \ +  }) +#define lll_robust_lock(futex, id, private) \ +  __lll_robust_lock (&(futex), id, private) + + +#define __lll_cond_lock(futex, private)					      \ +  ((void) ({								      \ +    int *__futex = (futex);						      \ +    if (__builtin_expect (atomic_exchange_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; + +#define __lll_timedlock(futex, abstime, private)			      \ +  ({									      \ +     int *__futex = (futex);						      \ +     int __val = 0;							      \ +									      \ +     if (__builtin_expect (atomic_exchange_acq (__futex, 1), 0))	      \ +       __val = __lll_timedlock_wait (__futex, abstime, private);	      \ +     __val;								      \ +  }) +#define lll_timedlock(futex, abstime, private) \ +  __lll_timedlock (&(futex), abstime, private) + + +#define __lll_robust_timedlock(futex, abstime, id, private)		      \ +  ({									      \ +    int *__futex = (futex);						      \ +    int __val = 0;							      \ +									      \ +    if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \ +								0), 0))	      \ +      __val = __lll_robust_timedlock_wait (__futex, abstime, private);	      \ +    __val;								      \ +  }) +#define lll_robust_timedlock(futex, abstime, id, private) \ +  __lll_robust_timedlock (&(futex), abstime, id, private) + + +#define __lll_unlock(futex, private) \ +  (void)							\ +    ({ int *__futex = (futex);					\ +       int __oldval = atomic_exchange_rel (__futex, 0);		\ +       if (__builtin_expect (__oldval > 1, 0))			\ +	 lll_futex_wake (__futex, 1, private);			\ +    }) +#define lll_unlock(futex, private) __lll_unlock(&(futex), private) + + +#define __lll_robust_unlock(futex, private) \ +  (void)							\ +    ({ int *__futex = (futex);					\ +       int __oldval = atomic_exchange_rel (__futex, 0);		\ +       if (__builtin_expect (__oldval & FUTEX_WAITERS, 0))	\ +	 lll_futex_wake (__futex, 1, private);			\ +    }) +#define lll_robust_unlock(futex, private) \ +  __lll_robust_unlock(&(futex), private) + + +#define lll_islocked(futex) \ +  (futex != 0) + + +/* Our internal lock implementation is identical to the binary-compatible +   mutex implementation. */ + +/* Initializers for lock.  */ +#define LLL_LOCK_INITIALIZER		(0) +#define LLL_LOCK_INITIALIZER_LOCKED	(1) + +/* The states of a lock are: +    0  -  untaken +    1  -  taken by one user +   >1  -  taken by more users */ + +/* The kernel notifies a process which uses CLONE_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(tid) \ +  do {					\ +    __typeof (tid) __tid;		\ +    while ((__tid = (tid)) != 0)	\ +      lll_futex_wait (&(tid), __tid, LLL_SHARED);\ +  } while (0) + +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;						\ +  }) + +#endif	/* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/nptl-aeabi_unwind_cpp_pr1.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/nptl-aeabi_unwind_cpp_pr1.c new file mode 100644 index 000000000..7b8352243 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/nptl-aeabi_unwind_cpp_pr1.c @@ -0,0 +1 @@ +#include <aeabi_unwind_cpp_pr1.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_error.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_error.c new file mode 100644 index 000000000..5a48a9b2e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_error.c @@ -0,0 +1 @@ +#include <../../../../../../../libc/sysdeps/linux/arm/__syscall_error.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_rt_sigaction.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_rt_sigaction.c new file mode 100644 index 000000000..50137c84a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_rt_sigaction.c @@ -0,0 +1 @@ +#include <../../../../../../../libc/sysdeps/linux/common/__syscall_rt_sigaction.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-gettimeofday.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-gettimeofday.c new file mode 100644 index 000000000..08710f1c8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-gettimeofday.c @@ -0,0 +1,5 @@ +#include <sys/syscall.h> +#include <sys/time.h> + +int gettimeofday (struct timeval *, struct timezone *) attribute_hidden; +_syscall2(int, gettimeofday, struct timeval *, tv, struct timezone *, tz); diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-vfork.S new file mode 100644 index 000000000..9764e9ee2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-vfork.S @@ -0,0 +1,38 @@ +/* Copyright (C) 2005 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <tcb-offsets.h> + +/* Save the PID value.  */ +#define SAVE_PID \ +	str	lr, [sp, #-4]!;		/* Save LR.  */			\ +	mov	r0, #0xffff0fff;	/* Point to the high page.  */	\ +	mov	lr, pc;			/* Save our return address.  */	\ +	sub	pc, r0, #31;		/* Jump to the TLS entry.  */	\ +	ldr	lr, [sp], #4;		/* Restore LR.  */		\ +	mov	r2, r0;			/* Save the TLS addr in r2.  */	\ +	ldr	r3, [r2, #PID_OFFSET];	/* Load the saved PID.  */	\ +	rsb	r0, r3, #0;		/* Negate it.  */		\ +	str	r0, [r2, #PID_OFFSET]	/* Store the temporary PID.  */ + +/* Restore the old PID value in the parent.  */ +#define RESTORE_PID \ +	cmp	r0, #0;			/* If we are the parent... */	\ +	strne	r3, [r2, #PID_OFFSET]	/* ... restore the saved PID.  */ + +#INCLUDE <../../../../../../../LIBC/SYSDEPS/LINUX/ARM/VFORK.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pthread_once.c new file mode 100644 index 000000000..e977a7d0c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pthread_once.c @@ -0,0 +1,100 @@ +/* Copyright (C) 2004, 2005 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#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 +attribute_protected +__pthread_once (pthread_once_t *once_control, void (*init_routine) (void)) +{ +  for (;;) +    { +      int oldval; +      int newval; + +      /* Pseudo code: +	 newval = __fork_generation | 1; +	 oldval = *once_control; +	 if ((oldval & 2) == 0) +	   *once_control = newval; +	 Do this atomically. +      */ +      do +	{ +	  newval = __fork_generation | 1; +	  oldval = *once_control; +	  if (oldval & 2) +	    break; +	} while (atomic_compare_and_exchange_val_acq (once_control, newval, oldval) != oldval); + +      /* Check if the initializer has already been done.  */ +      if ((oldval & 2) != 0) +	return 0; + +      /* Check if another thread already runs the initializer.	*/ +      if ((oldval & 1) == 0) +	break; + +      /* Check whether the initializer execution was interrupted by a fork.  */ +      if (oldval != newval) +	break; + +      /* Same generation, some other thread was faster. Wait.  */ +      lll_futex_wait (once_control, oldval, LLL_PRIVATE); +    } + +  /* 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); + +  /* Say that the initialisation is done.  */ +  *once_control = __fork_generation | 2; + +  /* Wake up all other threads.  */ +  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE); + +  return 0; +} +weak_alias (__pthread_once, pthread_once) +strong_alias (__pthread_once, __pthread_once_internal) + +#if defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__PIC__) +/* When statically linked, if pthread_create is used, this file +   will be brought in.  The exception handling code in GCC assumes +   that if pthread_create is available, so are these.  */ +const void *include_pthread_getspecific attribute_hidden = pthread_getspecific; +const void *include_pthread_setspecific attribute_hidden = pthread_setspecific; +const void *include_pthread_key_create attribute_hidden = pthread_key_create; +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h new file mode 100644 index 000000000..423c23195 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h @@ -0,0 +1,137 @@ +/* Copyright (C) 2003, 2004, 2005 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <tcb-offsets.h> +#ifndef __ASSEMBLER__ +# include <pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args)				\ +  .section ".text";							\ +    PSEUDO_PROLOGUE;							\ +  .type __##syscall_name##_nocancel,%function;				\ +  .globl __##syscall_name##_nocancel;					\ +  __##syscall_name##_nocancel:						\ +    DO_CALL (syscall_name, args);					\ +    PSEUDO_RET;								\ +  .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;	\ +  ENTRY (name);								\ +    SINGLE_THREAD_P;							\ +    DOARGS_##args;							\ +    bne .Lpseudo_cancel;						\ +    DO_CALL (syscall_name, 0);						\ +    UNDOARGS_##args;							\ +    cmn r0, $4096;							\ +    PSEUDO_RET;								\ +  .Lpseudo_cancel:							\ +    DOCARGS_##args;	/* save syscall args etc. around CENABLE.  */	\ +    CENABLE;								\ +    mov ip, r0;		/* put mask in safe place.  */			\ +    UNDOCARGS_##args;	/* restore syscall args.  */			\ +    swi SYS_ify (syscall_name);	/* do the call.  */			\ +    str r0, [sp, $-4]!; /* save syscall return value.  */		\ +    mov r0, ip;		/* get mask back.  */				\ +    CDISABLE;								\ +    ldmfd sp!, {r0, lr}; /* retrieve return value and address.  */	\ +    UNDOARGS_##args;							\ +    cmn r0, $4096; + +# define DOCARGS_0	str lr, [sp, #-4]!; +# define UNDOCARGS_0 + +# define DOCARGS_1	stmfd sp!, {r0, lr}; +# define UNDOCARGS_1	ldr r0, [sp], #4; + +# define DOCARGS_2	stmfd sp!, {r0, r1, lr}; +# define UNDOCARGS_2	ldmfd sp!, {r0, r1}; + +# define DOCARGS_3	stmfd sp!, {r0, r1, r2, lr}; +# define UNDOCARGS_3	ldmfd sp!, {r0, r1, r2}; + +# define DOCARGS_4	stmfd sp!, {r0, r1, r2, r3, lr}; +# define UNDOCARGS_4	ldmfd sp!, {r0, r1, r2, r3}; + +# define DOCARGS_5	DOCARGS_4 +# define UNDOCARGS_5	UNDOCARGS_4 + +# define DOCARGS_6	DOCARGS_5 +# define UNDOCARGS_6	UNDOCARGS_5 + +# ifdef IS_IN_libpthread +#  define CENABLE	bl PLTJMP(__pthread_enable_asynccancel) +#  define CDISABLE	bl PLTJMP(__pthread_disable_asynccancel) +#  define __local_multiple_threads __pthread_multiple_threads +# elif !defined NOT_IN_libc +#  define CENABLE	bl PLTJMP(__libc_enable_asynccancel) +#  define CDISABLE	bl PLTJMP(__libc_disable_asynccancel) +#  define __local_multiple_threads __libc_multiple_threads +# elif defined IS_IN_librt +#  define CENABLE	bl PLTJMP(__librt_enable_asynccancel) +#  define CDISABLE	bl PLTJMP(__librt_disable_asynccancel) +# else +#  error Unsupported library +# endif + +# 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						\ +  ldr ip, 1b;								\ +2:									\ +  ldr ip, [pc, ip];							\ +  teq ip, #0; +#   define PSEUDO_PROLOGUE						\ +  1:  .word __local_multiple_threads - 2f - 8; +#  endif +# else +/*  There is no __local_multiple_threads for librt, so use the TCB.  */ +#  ifndef __ASSEMBLER__ +#   define SINGLE_THREAD_P						\ +  __builtin_expect (THREAD_GETMEM (THREAD_SELF,				\ +				   header.multiple_threads) == 0, 1) +#  else +#   define PSEUDO_PROLOGUE +#   define SINGLE_THREAD_P						\ +  stmfd	sp!, {r0, lr};							\ +  bl	__aeabi_read_tp;						\ +  ldr	ip, [r0, #MULTIPLE_THREADS_OFFSET];				\ +  ldmfd	sp!, {r0, lr};							\ +  teq	ip, #0 +#   define SINGLE_THREAD_P_PIC(x) SINGLE_THREAD_P +#  endif +# endif + +#elif !defined __ASSEMBLER__ + +/* For rtld, et cetera.  */ +# 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/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c new file mode 100644 index 000000000..d095d3083 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c @@ -0,0 +1,149 @@ +/* Copyright (C) 2003, 2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Jakub Jelinek <jakub@redhat.com>. + +   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; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +#include <dlfcn.h> +#include <stdio.h> +#include <unwind.h> +#include <pthreadP.h> +#define __libc_dlopen(x)        dlopen(x, (RTLD_LOCAL | RTLD_LAZY)) +#define __libc_dlsym            dlsym +#define __libc_dlclose          dlclose + +static void *libgcc_s_handle; +static void (*libgcc_s_resume) (struct _Unwind_Exception *exc); +static _Unwind_Reason_Code (*libgcc_s_personality) +  (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *, +   struct _Unwind_Context *); +static _Unwind_Reason_Code (*libgcc_s_forcedunwind) +  (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *); +static _Unwind_Word (*libgcc_s_getcfa) (struct _Unwind_Context *); +static void (*libgcc_s_sjlj_register) (struct SjLj_Function_Context *); +static void (*libgcc_s_sjlj_unregister) (struct SjLj_Function_Context *); + +void +__attribute_noinline__ +pthread_cancel_init (void) +{ +  void *resume, *personality, *forcedunwind, *getcfa; +  void *handle; +  void *sjlj_register, *sjlj_unregister; + +  if (__builtin_expect (libgcc_s_handle != NULL, 1)) +    { +      /* Force gcc to reload all values.  */ +      asm volatile ("" ::: "memory"); +      return; +    } + +  handle = __libc_dlopen ("libgcc_s.so.1"); + +  if (handle == NULL +      || (sjlj_register = __libc_dlsym (handle, "_Unwind_SjLj_Register")) == NULL +      || (sjlj_unregister = __libc_dlsym (handle, "_Unwind_SjLj_Unregister")) == NULL +      || (resume = __libc_dlsym (handle, "_Unwind_SjLj_Resume")) == NULL +      || (personality = __libc_dlsym (handle, "__gcc_personality_sj0")) == NULL +      || (forcedunwind = __libc_dlsym (handle, "_Unwind_SjLj_ForcedUnwind")) +	 == NULL +      || (getcfa = __libc_dlsym (handle, "_Unwind_GetCFA")) == NULL +      ) +      fprintf(stderr, "libgcc_s.so.1 must be installed for pthread_cancel to work\n"); + +  libgcc_s_resume = resume; +  libgcc_s_personality = personality; +  libgcc_s_forcedunwind = forcedunwind; +  libgcc_s_sjlj_register = sjlj_register; +  libgcc_s_sjlj_unregister = sjlj_unregister; +  libgcc_s_getcfa = getcfa; +  /* Make sure libgcc_s_getcfa is written last.  Otherwise, +     pthread_cancel_init might return early even when the pointer the +     caller is interested in is not initialized yet.  */ +  atomic_write_barrier (); +  libgcc_s_handle = handle; +} + +void +__libc_freeres_fn_section +__unwind_freeres (void) +{ +  void *handle = libgcc_s_handle; +  if (handle != NULL) +    { +      libgcc_s_handle = NULL; +      __libc_dlclose (handle); +    } +} + +void +_Unwind_Resume (struct _Unwind_Exception *exc) +{ +  if (__builtin_expect (libgcc_s_resume == NULL, 0)) +    pthread_cancel_init (); + +  libgcc_s_resume (exc); +} + +_Unwind_Reason_Code +__gcc_personality_v0 (int version, _Unwind_Action actions, +		      _Unwind_Exception_Class exception_class, +                      struct _Unwind_Exception *ue_header, +                      struct _Unwind_Context *context) +{ +  if (__builtin_expect (libgcc_s_personality == NULL, 0)) +    pthread_cancel_init (); + +  return libgcc_s_personality (version, actions, exception_class, +			       ue_header, context); +} + +_Unwind_Reason_Code +_Unwind_ForcedUnwind (struct _Unwind_Exception *exc, _Unwind_Stop_Fn stop, +		      void *stop_argument) +{ +  if (__builtin_expect (libgcc_s_forcedunwind == NULL, 0)) +    pthread_cancel_init (); + +  return libgcc_s_forcedunwind (exc, stop, stop_argument); +} + +_Unwind_Word +_Unwind_GetCFA (struct _Unwind_Context *context) +{ +  if (__builtin_expect (libgcc_s_getcfa == NULL, 0)) +    pthread_cancel_init (); + +  return libgcc_s_getcfa (context); +} + +void +_Unwind_SjLj_Register (struct SjLj_Function_Context *fc) +{ +  if (__builtin_expect (libgcc_s_sjlj_register == NULL, 0)) +    pthread_cancel_init (); + +  libgcc_s_sjlj_register (fc); +} + +void +_Unwind_SjLj_Unregister (struct SjLj_Function_Context *fc) +{ +  if (__builtin_expect (libgcc_s_sjlj_unregister == NULL, 0)) +    pthread_cancel_init (); + +  libgcc_s_sjlj_unregister (fc); +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-resume.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-resume.c new file mode 100644 index 000000000..bf0348ac2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-resume.c @@ -0,0 +1,90 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Jakub Jelinek <jakub@redhat.com>. + +   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; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +#include <dlfcn.h> +#include <stdio.h> +#include <unwind.h> +#define __libc_dlopen(x)        dlopen(x, (RTLD_LOCAL | RTLD_LAZY)) +#define __libc_dlsym            dlsym +#define __libc_dlclose		dlclose + +static void (*libgcc_s_resume) (struct _Unwind_Exception *exc); +static _Unwind_Reason_Code (*libgcc_s_personality) +  (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *, +   struct _Unwind_Context *); +static void (*libgcc_s_sjlj_register) (struct SjLj_Function_Context *); +static void (*libgcc_s_sjlj_unregister) (struct SjLj_Function_Context *); + +static void +init (void) +{ +  void *resume, *personality; +  void *handle; +  void *sjlj_register, *sjlj_unregister; + +  handle = __libc_dlopen ("libgcc_s.so.1"); + +  if (handle == NULL +      || (sjlj_register = __libc_dlsym (handle, "_Unwind_SjLj_Register")) == NULL +      || (sjlj_unregister = __libc_dlsym (handle, "_Unwind_SjLj_Unregister")) == NULL +      || (resume = __libc_dlsym (handle, "_Unwind_SjLj_Resume")) == NULL +      || (personality = __libc_dlsym (handle, "__gcc_personality_sj0")) == NULL) +      fprintf(stderr, "libgcc_s.so.1 must be installed for pthread_cancel to work\n"); + +  libgcc_s_resume = resume; +  libgcc_s_personality = personality; +  libgcc_s_sjlj_register = sjlj_register; +  libgcc_s_sjlj_unregister = sjlj_unregister; +} + +void +_Unwind_Resume (struct _Unwind_Exception *exc) +{ +  if (__builtin_expect (libgcc_s_resume == NULL, 0)) +    init (); +  libgcc_s_resume (exc); +} + +_Unwind_Reason_Code +__gcc_personality_v0 (int version, _Unwind_Action actions, +		      _Unwind_Exception_Class exception_class, +                      struct _Unwind_Exception *ue_header, +                      struct _Unwind_Context *context) +{ +  if (__builtin_expect (libgcc_s_personality == NULL, 0)) +    init (); +  return libgcc_s_personality (version, actions, exception_class, +			       ue_header, context); +} + +void +_Unwind_SjLj_Register (struct SjLj_Function_Context *fc) +{ +  if (__builtin_expect (libgcc_s_sjlj_register == NULL, 0)) +    init (); +  libgcc_s_sjlj_register (fc); +} + +void +_Unwind_SjLj_Unregister (struct SjLj_Function_Context *fc) +{ +  if (__builtin_expect (libgcc_s_sjlj_unregister == NULL, 0)) +    init (); +  libgcc_s_sjlj_unregister (fc); +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind.h new file mode 100644 index 000000000..eeb9cf8b6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind.h @@ -0,0 +1,279 @@ +/* Header file for the ARM EABI unwinder +   Copyright (C) 2003, 2004, 2005, 2009  Free Software Foundation, Inc. +   Contributed by Paul Brook + +   This file is free software; you can redistribute it and/or modify it +   under the terms of the GNU General Public License as published by the +   Free Software Foundation; either version 2, or (at your option) any +   later version. + +   In addition to the permissions in the GNU General Public License, the +   Free Software Foundation gives you unlimited permission to link the +   compiled version of this file into combinations with other programs, +   and to distribute those combinations without any restriction coming +   from the use of this file.  (The General Public License restrictions +   do apply in other respects; for example, they cover modification of +   the file, and distribution when not linked into a combine +   executable.) + +   This file 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 +   General Public License for more details. + +   You should have received a copy of the GNU General Public License +   along with this program; see the file COPYING.  If not, write to +   the Free Software Foundation, 51 Franklin Street, Fifth Floor, +   Boston, MA 02110-1301, USA.  */ + +/* Language-independent unwinder header public defines.  This contains both +   ABI defined objects, and GNU support routines.  */ + +#ifndef UNWIND_ARM_H +#define UNWIND_ARM_H + +#define __ARM_EABI_UNWINDER__ 1 + +#ifdef __cplusplus +extern "C" { +#endif +  typedef unsigned _Unwind_Word __attribute__((__mode__(__word__))); +  typedef signed _Unwind_Sword __attribute__((__mode__(__word__))); +  typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__))); +  typedef unsigned _Unwind_Internal_Ptr __attribute__((__mode__(__pointer__))); +  typedef _Unwind_Word _uw; +  typedef unsigned _uw64 __attribute__((mode(__DI__))); +  typedef unsigned _uw16 __attribute__((mode(__HI__))); +  typedef unsigned _uw8 __attribute__((mode(__QI__))); + +  typedef enum +    { +      _URC_OK = 0,       /* operation completed successfully */ +      _URC_FOREIGN_EXCEPTION_CAUGHT = 1, +      _URC_END_OF_STACK = 5, +      _URC_HANDLER_FOUND = 6, +      _URC_INSTALL_CONTEXT = 7, +      _URC_CONTINUE_UNWIND = 8, +      _URC_FAILURE = 9   /* unspecified failure of some kind */ +    } +  _Unwind_Reason_Code; + +  typedef enum +    { +      _US_VIRTUAL_UNWIND_FRAME = 0, +      _US_UNWIND_FRAME_STARTING = 1, +      _US_UNWIND_FRAME_RESUME = 2, +      _US_ACTION_MASK = 3, +      _US_FORCE_UNWIND = 8, +      _US_END_OF_STACK = 16 +    } +  _Unwind_State; + +  /* Provided only for for compatibility with existing code.  */ +  typedef int _Unwind_Action; +#define _UA_SEARCH_PHASE	1 +#define _UA_CLEANUP_PHASE	2 +#define _UA_HANDLER_FRAME	4 +#define _UA_FORCE_UNWIND	8 +#define _UA_END_OF_STACK	16 +#define _URC_NO_REASON 	_URC_OK + +  typedef struct _Unwind_Control_Block _Unwind_Control_Block; +  typedef struct _Unwind_Context _Unwind_Context; +  typedef _uw _Unwind_EHT_Header; + + +  /* UCB: */ + +  struct _Unwind_Control_Block +    { +#ifdef _LIBC +      /* For the benefit of code which assumes this is a scalar.  All +	 glibc ever does is clear it.  */ +      _uw64 exception_class; +#else +      char exception_class[8]; +#endif +      void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block *); +      /* Unwinder cache, private fields for the unwinder's use */ +      struct +	{ +	  _uw reserved1;  /* Forced unwind stop fn, 0 if not forced */ +	  _uw reserved2;  /* Personality routine address */ +	  _uw reserved3;  /* Saved callsite address */ +	  _uw reserved4;  /* Forced unwind stop arg */ +	  _uw reserved5; +	} +      unwinder_cache; +      /* Propagation barrier cache (valid after phase 1): */ +      struct +	{ +	  _uw sp; +	  _uw bitpattern[5]; +	} +      barrier_cache; +      /* Cleanup cache (preserved over cleanup): */ +      struct +	{ +	  _uw bitpattern[4]; +	} +      cleanup_cache; +      /* Pr cache (for pr's benefit): */ +      struct +	{ +	  _uw fnstart;			/* function start address */ +	  _Unwind_EHT_Header *ehtp;	/* pointer to EHT entry header word */ +	  _uw additional;		/* additional data */ +	  _uw reserved1; +	} +      pr_cache; +      long long int :0;	/* Force alignment to 8-byte boundary */ +    }; + +  /* Virtual Register Set*/ + +  typedef enum +    { +      _UVRSC_CORE = 0,      /* integer register */ +      _UVRSC_VFP = 1,       /* vfp */ +      _UVRSC_FPA = 2,       /* fpa */ +      _UVRSC_WMMXD = 3,     /* Intel WMMX data register */ +      _UVRSC_WMMXC = 4      /* Intel WMMX control register */ +    } +  _Unwind_VRS_RegClass; + +  typedef enum +    { +      _UVRSD_UINT32 = 0, +      _UVRSD_VFPX = 1, +      _UVRSD_FPAX = 2, +      _UVRSD_UINT64 = 3, +      _UVRSD_FLOAT = 4, +      _UVRSD_DOUBLE = 5 +    } +  _Unwind_VRS_DataRepresentation; + +  typedef enum +    { +      _UVRSR_OK = 0, +      _UVRSR_NOT_IMPLEMENTED = 1, +      _UVRSR_FAILED = 2 +    } +  _Unwind_VRS_Result; + +  /* Frame unwinding state.  */ +  typedef struct +    { +      /* The current word (bytes packed msb first).  */ +      _uw data; +      /* Pointer to the next word of data.  */ +      _uw *next; +      /* The number of bytes left in this word.  */ +      _uw8 bytes_left; +      /* The number of words pointed to by ptr.  */ +      _uw8 words_left; +    } +  __gnu_unwind_state; + +  typedef _Unwind_Reason_Code (*personality_routine) (_Unwind_State, +      _Unwind_Control_Block *, _Unwind_Context *); + +  _Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context *, _Unwind_VRS_RegClass, +                                     _uw, _Unwind_VRS_DataRepresentation, +                                     void *); + +  _Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *, _Unwind_VRS_RegClass, +                                     _uw, _Unwind_VRS_DataRepresentation, +                                     void *); + +  _Unwind_VRS_Result _Unwind_VRS_Pop(_Unwind_Context *, _Unwind_VRS_RegClass, +                                     _uw, _Unwind_VRS_DataRepresentation); + + +  /* Support functions for the PR.  */ +#define _Unwind_Exception _Unwind_Control_Block +  typedef char _Unwind_Exception_Class[8]; + +  void * _Unwind_GetLanguageSpecificData (_Unwind_Context *); +  _Unwind_Ptr _Unwind_GetRegionStart (_Unwind_Context *); + +  /* These two should never be used.  */ +  _Unwind_Ptr _Unwind_GetDataRelBase (_Unwind_Context *); +  _Unwind_Ptr _Unwind_GetTextRelBase (_Unwind_Context *); + +  /* Interface functions: */ +  _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Control_Block *ucbp); +  void __attribute__((noreturn)) _Unwind_Resume(_Unwind_Control_Block *ucbp); +  _Unwind_Reason_Code _Unwind_Resume_or_Rethrow (_Unwind_Control_Block *ucbp); + +  typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) +       (int, _Unwind_Action, _Unwind_Exception_Class, +	_Unwind_Control_Block *, struct _Unwind_Context *, void *); +  _Unwind_Reason_Code _Unwind_ForcedUnwind (_Unwind_Control_Block *, +					    _Unwind_Stop_Fn, void *); +  _Unwind_Word _Unwind_GetCFA (struct _Unwind_Context *); +  void _Unwind_Complete(_Unwind_Control_Block *ucbp); +  void _Unwind_DeleteException (_Unwind_Exception *); + +  _Unwind_Reason_Code __gnu_unwind_frame (_Unwind_Control_Block *, +					  _Unwind_Context *); +  _Unwind_Reason_Code __gnu_unwind_execute (_Unwind_Context *, +					    __gnu_unwind_state *); + +  /* Decode an R_ARM_TARGET2 relocation.  */ +  static inline _Unwind_Word +  _Unwind_decode_target2 (_Unwind_Word ptr) +    { +      _Unwind_Word tmp; + +      tmp = *(_Unwind_Word *) ptr; +      /* Zero values are always NULL.  */ +      if (!tmp) +	return 0; + +#if defined(linux) || defined(__NetBSD__) +      /* Pc-relative indirect.  */ +      tmp += ptr; +      tmp = *(_Unwind_Word *) tmp; +#elif defined(__symbian__) +      /* Absolute pointer.  Nothing more to do.  */ +#else +      /* Pc-relative pointer.  */ +      tmp += ptr; +#endif +      return tmp; +    } + +  static inline _Unwind_Word +  _Unwind_GetGR (_Unwind_Context *context, int regno) +    { +      _uw val; +      _Unwind_VRS_Get (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val); +      return val; +    } + +  /* Return the address of the instruction, not the actual IP value.  */ +#define _Unwind_GetIP(context) \ +  (_Unwind_GetGR (context, 15) & ~(_Unwind_Word)1) + +  static inline void +  _Unwind_SetGR (_Unwind_Context *context, int regno, _Unwind_Word val) +    { +      _Unwind_VRS_Set (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val); +    } + +  /* The dwarf unwinder doesn't understand arm/thumb state.  We assume the +     landing pad uses the same instruction set as the call site.  */ +#define _Unwind_SetIP(context, val) \ +  _Unwind_SetGR (context, 15, val | (_Unwind_GetGR (context, 15) & 1)) + +typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) +     (struct _Unwind_Context *, void *); + +extern _Unwind_Reason_Code _Unwind_Backtrace (_Unwind_Trace_Fn, void *); + +#ifdef __cplusplus +}   /* extern "C" */ +#endif + +#endif /* defined UNWIND_ARM_H */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/vfork.S new file mode 100644 index 000000000..935a4e904 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/vfork.S @@ -0,0 +1,39 @@ +/* Copyright (C) 2005 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <tcb-offsets.h> + +/* Save the PID value.  */ +#define SAVE_PID \ +	str	lr, [sp, #-4]!;		/* Save LR.  */			\ +	mov	r0, #0xffff0fff;	/* Point to the high page.  */	\ +	mov	lr, pc;			/* Save our return address.  */	\ +	sub	pc, r0, #31;		/* Jump to the TLS entry.  */	\ +	ldr	lr, [sp], #4;		/* Restore LR.  */		\ +	mov	r2, r0;			/* Save the TLS addr in r2.  */	\ +	ldr	r3, [r2, #PID_OFFSET];	/* Load the saved PID.  */	\ +	rsbs	r0, r3, #0;		/* Negate it.  */		\ +	moveq	r0, #0x80000000;	/* Use 0x80000000 if it was 0.  */ \ +	str	r0, [r2, #PID_OFFSET]	/* Store the temporary PID.  */ + +/* Restore the old PID value in the parent.  */ +#define RESTORE_PID \ +	cmp	r0, #0;			/* If we are the parent... */	\ +	strne	r3, [r2, #PID_OFFSET]	/* ... restore the saved PID.  */ + +#include "../../../../../../../libc/sysdeps/linux/arm/vfork.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/bits/local_lim.h b/libpthread/nptl/sysdeps/unix/sysv/linux/bits/local_lim.h new file mode 100644 index 000000000..8f0df4f92 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/bits/local_lim.h @@ -0,0 +1,100 @@ +/* Minimum guaranteed maximum values for system limits.  Linux version. +   Copyright (C) 1993-1998,2000,2002-2004,2008 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; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +/* The kernel header pollutes the namespace with the NR_OPEN symbol +   and defines LINK_MAX although filesystems have different maxima.  A +   similar thing is true for OPEN_MAX: the limit can be changed at +   runtime and therefore the macro must not be defined.  Remove this +   after including the header if necessary.  */ +#ifndef NR_OPEN +# define __undef_NR_OPEN +#endif +#ifndef LINK_MAX +# define __undef_LINK_MAX +#endif +#ifndef OPEN_MAX +# define __undef_OPEN_MAX +#endif +#ifndef ARG_MAX +# define __undef_ARG_MAX +#endif + +/* The kernel sources contain a file with all the needed information.  */ +#include <linux/limits.h> + +/* Have to remove NR_OPEN?  */ +#ifdef __undef_NR_OPEN +# undef NR_OPEN +# undef __undef_NR_OPEN +#endif +/* Have to remove LINK_MAX?  */ +#ifdef __undef_LINK_MAX +# undef LINK_MAX +# undef __undef_LINK_MAX +#endif +/* Have to remove OPEN_MAX?  */ +#ifdef __undef_OPEN_MAX +# undef OPEN_MAX +# undef __undef_OPEN_MAX +#endif +/* Have to remove ARG_MAX?  */ +#ifdef __undef_ARG_MAX +# undef ARG_MAX +# undef __undef_ARG_MAX +#endif + +/* The number of data keys per process.  */ +#define _POSIX_THREAD_KEYS_MAX	128 +/* This is the value this implementation supports.  */ +#define PTHREAD_KEYS_MAX	1024 + +/* Controlling the iterations of destructors for thread-specific data.  */ +#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS	4 +/* Number of iterations this implementation does.  */ +#define PTHREAD_DESTRUCTOR_ITERATIONS	_POSIX_THREAD_DESTRUCTOR_ITERATIONS + +/* The number of threads per process.  */ +#define _POSIX_THREAD_THREADS_MAX	64 +/* We have no predefined limit on the number of threads.  */ +#undef PTHREAD_THREADS_MAX + +/* Maximum amount by which a process can descrease its asynchronous I/O +   priority level.  */ +#define AIO_PRIO_DELTA_MAX	20 + +/* Minimum size for a thread.  We are free to choose a reasonable value.  */ +#define PTHREAD_STACK_MIN	16384 + +/* Maximum number of timer expiration overruns.  */ +#define DELAYTIMER_MAX	2147483647 + +/* Maximum tty name length.  */ +#define TTY_NAME_MAX		32 + +/* Maximum login name length.  This is arbitrary.  */ +#define LOGIN_NAME_MAX		256 + +/* Maximum host name length.  */ +#define HOST_NAME_MAX		64 + +/* Maximum message queue priority level.  */ +#define MQ_PRIO_MAX		32768 + +/* Maximum value the semaphore can have.  */ +#define SEM_VALUE_MAX   (2147483647) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h b/libpthread/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h new file mode 100644 index 000000000..2550355cd --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h @@ -0,0 +1,192 @@ +/* Define POSIX options for Linux. +   Copyright (C) 1996-2004, 2006, 2008, 2009 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; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +#ifndef	_BITS_POSIX_OPT_H +#define	_BITS_POSIX_OPT_H	1 + +/* Job control is supported.  */ +#define	_POSIX_JOB_CONTROL	1 + +/* Processes have a saved set-user-ID and a saved set-group-ID.  */ +#define	_POSIX_SAVED_IDS	1 + +/* Priority scheduling is supported.  */ +#define	_POSIX_PRIORITY_SCHEDULING	200809L + +/* Synchronizing file data is supported.  */ +#define	_POSIX_SYNCHRONIZED_IO	200809L + +/* The fsync function is present.  */ +#define	_POSIX_FSYNC	200809L + +/* Mapping of files to memory is supported.  */ +#define	_POSIX_MAPPED_FILES	200809L + +/* Locking of all memory is supported.  */ +#define	_POSIX_MEMLOCK	200809L + +/* Locking of ranges of memory is supported.  */ +#define	_POSIX_MEMLOCK_RANGE	200809L + +/* Setting of memory protections is supported.  */ +#define	_POSIX_MEMORY_PROTECTION	200809L + +/* Some filesystems allow all users to change file ownership.  */ +#define	_POSIX_CHOWN_RESTRICTED	0 + +/* `c_cc' member of 'struct termios' structure can be disabled by +   using the value _POSIX_VDISABLE.  */ +#define	_POSIX_VDISABLE	'\0' + +/* Filenames are not silently truncated.  */ +#define	_POSIX_NO_TRUNC	1 + +/* X/Open realtime support is available.  */ +#define _XOPEN_REALTIME	1 + +/* X/Open thread realtime support is available.  */ +#define _XOPEN_REALTIME_THREADS	1 + +/* XPG4.2 shared memory is supported.  */ +#define	_XOPEN_SHM	1 + +/* Tell we have POSIX threads.  */ +#define _POSIX_THREADS	200809L + +/* We have the reentrant functions described in POSIX.  */ +#define _POSIX_REENTRANT_FUNCTIONS      1 +#define _POSIX_THREAD_SAFE_FUNCTIONS	200809L + +/* We provide priority scheduling for threads.  */ +#define _POSIX_THREAD_PRIORITY_SCHEDULING	200809L + +/* We support user-defined stack sizes.  */ +#define _POSIX_THREAD_ATTR_STACKSIZE	200809L + +/* We support user-defined stacks.  */ +#define _POSIX_THREAD_ATTR_STACKADDR	200809L + +/* We support priority inheritence.  */ +#define _POSIX_THREAD_PRIO_INHERIT	200809L + +/* We support priority protection, though only for non-robust +   mutexes.  */ +#define _POSIX_THREAD_PRIO_PROTECT	200809L + +#ifdef __USE_XOPEN2K8 +/* We support priority inheritence for robust mutexes.  */ +# define _POSIX_THREAD_ROBUST_PRIO_INHERIT	200809L + +/* We do not support priority protection for robust mutexes.  */ +# define _POSIX_THREAD_ROBUST_PRIO_PROTECT	-1 +#endif + +/* We support POSIX.1b semaphores.  */ +#define _POSIX_SEMAPHORES	200809L + +/* Real-time signals are supported.  */ +#define _POSIX_REALTIME_SIGNALS	200809L + +/* We support asynchronous I/O.  */ +#define _POSIX_ASYNCHRONOUS_IO	200809L +#define _POSIX_ASYNC_IO		1 +/* Alternative name for Unix98.  */ +#define _LFS_ASYNCHRONOUS_IO	1 +/* Support for prioritization is also available.  */ +#define _POSIX_PRIORITIZED_IO	200809L + +/* The LFS support in asynchronous I/O is also available.  */ +#define _LFS64_ASYNCHRONOUS_IO	1 + +/* The rest of the LFS is also available.  */ +#define _LFS_LARGEFILE		1 +#define _LFS64_LARGEFILE	1 +#define _LFS64_STDIO		1 + +/* POSIX shared memory objects are implemented.  */ +#define _POSIX_SHARED_MEMORY_OBJECTS	200809L + +/* CPU-time clocks support needs to be checked at runtime.  */ +#define _POSIX_CPUTIME	0 + +/* Clock support in threads must be also checked at runtime.  */ +#define _POSIX_THREAD_CPUTIME	0 + +/* GNU libc provides regular expression handling.  */ +#define _POSIX_REGEXP	1 + +/* Reader/Writer locks are available.  */ +#define _POSIX_READER_WRITER_LOCKS	200809L + +/* We have a POSIX shell.  */ +#define _POSIX_SHELL	1 + +/* We support the Timeouts option.  */ +#define _POSIX_TIMEOUTS	200809L + +/* We support spinlocks.  */ +#define _POSIX_SPIN_LOCKS	200809L + +/* The `spawn' function family is supported.  */ +#define _POSIX_SPAWN	200809L + +/* We have POSIX timers.  */ +#define _POSIX_TIMERS	200809L + +/* The barrier functions are available.  */ +#define _POSIX_BARRIERS	200809L + +/* POSIX message queues are available.  */ +#define	_POSIX_MESSAGE_PASSING	200809L + +/* Thread process-shared synchronization is supported.  */ +#define _POSIX_THREAD_PROCESS_SHARED	200809L + +/* The monotonic clock might be available.  */ +#define _POSIX_MONOTONIC_CLOCK	0 + +/* The clock selection interfaces are available.  */ +#define _POSIX_CLOCK_SELECTION	200809L + +/* Advisory information interfaces are available.  */ +#define _POSIX_ADVISORY_INFO	200809L + +/* IPv6 support is available.  */ +#define _POSIX_IPV6	200809L + +/* Raw socket support is available.  */ +#define _POSIX_RAW_SOCKETS	200809L + +/* We have at least one terminal.  */ +#define _POSIX2_CHAR_TERM	200809L + +/* Neither process nor thread sporadic server interfaces is available.  */ +#define _POSIX_SPORADIC_SERVER	-1 +#define _POSIX_THREAD_SPORADIC_SERVER	-1 + +/* trace.h is not available.  */ +#define _POSIX_TRACE	-1 +#define _POSIX_TRACE_EVENT_FILTER	-1 +#define _POSIX_TRACE_INHERIT	-1 +#define _POSIX_TRACE_LOG	-1 + +/* Typed memory objects are not available.  */ +#define _POSIX_TYPED_MEMORY_OBJECTS	-1 + +#endif /* bits/posix_opt.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/close.S b/libpthread/nptl/sysdeps/unix/sysv/linux/close.S new file mode 100644 index 000000000..cf50a1eae --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/close.S @@ -0,0 +1,21 @@ +#include <sysdep-cancel.h> + +/* +extern int __close_nocancel (int) attribute_hidden; +*/ +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + + +PSEUDO (__libc_close, close, 1) +ret +PSEUDO_END(__libc_close) + +libc_hidden_def (__close_nocancel) +libc_hidden_def (__libc_close) +weak_alias (__libc_close, __close) +libc_hidden_weak (__close) +weak_alias (__libc_close, close) +libc_hidden_weak (close) + + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/connect.S b/libpthread/nptl/sysdeps/unix/sysv/linux/connect.S new file mode 100644 index 000000000..441843fa0 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/connect.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_connect +#error Missing definition of NR_connect needed for cancellation. +#endif +PSEUDO (__libc_connect, connect, 3) +ret +PSEUDO_END(__libc_connect) +libc_hidden_def (__libc_connect) +weak_alias (__libc_connect, __connect) +libc_hidden_weak (__connect) +weak_alias (__libc_connect, connect) +libc_hidden_weak (connect) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/creat.S b/libpthread/nptl/sysdeps/unix/sysv/linux/creat.S new file mode 100644 index 000000000..cd0e1b879 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/creat.S @@ -0,0 +1,7 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_creat, creat, 2) +ret +PSEUDO_END(__libc_creat) +libc_hidden_def (__libc_creat) +weak_alias (__libc_creat, creat) +libc_hidden_weak (creat) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/createthread.c new file mode 100644 index 000000000..9149efe58 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/createthread.c @@ -0,0 +1,24 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>. + +   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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +/* Value passed to 'clone' for initialization of the thread register.  */ +#define TLS_VALUE pd + +/* Get the real implementation.	 */ +#include <sysdeps/pthread/createthread.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/exit-thread.S b/libpthread/nptl/sysdeps/unix/sysv/linux/exit-thread.S new file mode 100644 index 000000000..bb996fecf --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/exit-thread.S @@ -0,0 +1,23 @@ +/* Copyright (C) 1991,92,97,99,2002 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> + +PSEUDO (__exit_thread, exit, 1) +	/* Shouldn't get here.  */ +PSEUDO_END(__exit_thread) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/fork.c new file mode 100644 index 000000000..2d4cae224 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/fork.c @@ -0,0 +1,229 @@ +/* Copyright (C) 2002, 2003, 2007, 2008 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sysdep.h> +#include <tls.h> +#include "fork.h" +#include <hp-timing.h> +#include <ldsodefs.h> +#include <atomic.h> +#include <errno.h> + +unsigned long int *__fork_generation_pointer; + + + +/* The single linked list of all currently registered for handlers.  */ +struct fork_handler *__fork_handlers; + + +static void +fresetlockfiles (void) +{ +  FILE *fp; +#ifdef __USE_STDIO_FUTEXES__ +  for (fp = _stdio_openlist; fp != NULL; fp = fp->__nextopen) +    STDIO_INIT_MUTEX(fp->__lock); +#else +  pthread_mutexattr_t attr; + +  pthread_mutexattr_init(&attr); +  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); + +  for (fp = _stdio_openlist; fp != NULL; fp = fp->__nextopen) +    pthread_mutex_init(&fp->__lock, &attr); + +  pthread_mutexattr_destroy(&attr); +#endif +} + + +pid_t +__libc_fork (void) +{ +  pid_t pid; +  struct used_handler +  { +    struct fork_handler *handler; +    struct used_handler *next; +  } *allp = NULL; + +  /* Run all the registered preparation handlers.  In reverse order. +     While doing this we build up a list of all the entries.  */ +  struct fork_handler *runp; +  while ((runp = __fork_handlers) != NULL) +    { +      /* Make sure we read from the current RUNP pointer.  */ +      atomic_full_barrier (); + +      unsigned int oldval = runp->refcntr; + +      if (oldval == 0) +	/* This means some other thread removed the list just after +	   the pointer has been loaded.  Try again.  Either the list +	   is empty or we can retry it.  */ +	continue; + +      /* Bump the reference counter.  */ +      if (atomic_compare_and_exchange_bool_acq (&__fork_handlers->refcntr, +						oldval + 1, oldval)) +	/* The value changed, try again.  */ +	continue; + +      /* We bumped the reference counter for the first entry in the +	 list.  That means that none of the following entries will +	 just go away.  The unloading code works in the order of the +	 list. + +         While executing the registered handlers we are building a +         list of all the entries so that we can go backward later on.  */ +      while (1) +	{ +	  /* Execute the handler if there is one.  */ +	  if (runp->prepare_handler != NULL) +	    runp->prepare_handler (); + +	  /* Create a new element for the list.  */ +	  struct used_handler *newp +	    = (struct used_handler *) alloca (sizeof (*newp)); +	  newp->handler = runp; +	  newp->next = allp; +	  allp = newp; + +	  /* Advance to the next handler.  */ +	  runp = runp->next; +	  if (runp == NULL) +	    break; + +	  /* Bump the reference counter for the next entry.  */ +	  atomic_increment (&runp->refcntr); +	} + +      /* We are done.  */ +      break; +    } + +  __UCLIBC_IO_MUTEX_LOCK_CANCEL_UNSAFE(_stdio_openlist_add_lock); + +#ifndef NDEBUG +  pid_t ppid = THREAD_GETMEM (THREAD_SELF, tid); +#endif + +  /* We need to prevent the getpid() code to update the PID field so +     that, if a signal arrives in the child very early and the signal +     handler uses getpid(), the value returned is correct.  */ +  pid_t parentpid = THREAD_GETMEM (THREAD_SELF, pid); +  THREAD_SETMEM (THREAD_SELF, pid, -parentpid); + +#ifdef ARCH_FORK +  pid = ARCH_FORK (); +#else +# error "ARCH_FORK must be defined so that the CLONE_SETTID flag is used" +  pid = INLINE_SYSCALL (fork, 0); +#endif + + +  if (pid == 0) +    { +      struct pthread *self = THREAD_SELF; + +      assert (THREAD_GETMEM (self, tid) != ppid); + +      if (__fork_generation_pointer != NULL) +	*__fork_generation_pointer += 4; + +      /* Adjust the PID field for the new process.  */ +      THREAD_SETMEM (self, pid, THREAD_GETMEM (self, tid)); + +#if HP_TIMING_AVAIL +      /* The CPU clock of the thread and process have to be set to zero.  */ +      hp_timing_t now; +      HP_TIMING_NOW (now); +      THREAD_SETMEM (self, cpuclock_offset, now); +      GL(dl_cpuclock_offset) = now; +#endif + +      /* Reset the file list.  These are recursive mutexes.  */ +      fresetlockfiles (); + +      /* Reset locks in the I/O code.  */ +      STDIO_INIT_MUTEX(_stdio_openlist_add_lock); + +      /* XXX reset any locks in dynamic loader */ + +      /* Run the handlers registered for the child.  */ +      while (allp != NULL) +	{ +	  if (allp->handler->child_handler != NULL) +	    allp->handler->child_handler (); + +	  /* Note that we do not have to wake any possible waiter. + 	     This is the only thread in the new process.  The count + 	     may have been bumped up by other threads doing a fork. + 	     We reset it to 1, to avoid waiting for non-existing + 	     thread(s) to release the count.  */ +	  allp->handler->refcntr = 1; + +	  /* XXX We could at this point look through the object pool +	     and mark all objects not on the __fork_handlers list as +	     unused.  This is necessary in case the fork() happened +	     while another thread called dlclose() and that call had +	     to create a new list.  */ + +	  allp = allp->next; +	} + +      /* Initialize the fork lock.  */ +      __fork_lock = LLL_LOCK_INITIALIZER; +    } +  else +    { +      assert (THREAD_GETMEM (THREAD_SELF, tid) == ppid); + +      /* Restore the PID value.  */ +      THREAD_SETMEM (THREAD_SELF, pid, parentpid); + +      /* We execute this even if the 'fork' call failed.  */ +      __UCLIBC_IO_MUTEX_UNLOCK_CANCEL_UNSAFE(_stdio_openlist_add_lock); + +      /* Run the handlers registered for the parent.  */ +      while (allp != NULL) +	{ +	  if (allp->handler->parent_handler != NULL) +	    allp->handler->parent_handler (); + +	  if (atomic_decrement_and_test (&allp->handler->refcntr) +	      && allp->handler->need_signal) +	    lll_futex_wake (allp->handler->refcntr, 1, LLL_PRIVATE); + +	  allp = allp->next; +	} +    } + +  return pid; +} +weak_alias(__libc_fork,__fork) +libc_hidden_proto(fork) +weak_alias(__libc_fork,fork) +libc_hidden_weak(fork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/fork.h b/libpthread/nptl/sysdeps/unix/sysv/linux/fork.h new file mode 100644 index 000000000..a00cfabe2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/fork.h @@ -0,0 +1,60 @@ +/* Copyright (C) 2002, 2003, 2006, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <lowlevellock.h> + +/* The fork generation counter, defined in libpthread.  */ +extern unsigned long int __fork_generation attribute_hidden; + +/* Pointer to the fork generation counter in the thread library.  */ +extern unsigned long int *__fork_generation_pointer attribute_hidden; + +/* Lock to protect allocation and deallocation of fork handlers.  */ +extern int __fork_lock attribute_hidden; + +/* Elements of the fork handler lists.  */ +struct fork_handler +{ +  struct fork_handler *next; +  void (*prepare_handler) (void); +  void (*parent_handler) (void); +  void (*child_handler) (void); +  void *dso_handle; +  unsigned int refcntr; +  int need_signal; +}; + +/* The single linked list of all currently registered for handlers.  */ +extern struct fork_handler *__fork_handlers attribute_hidden; + + +/* Function to call to unregister fork handlers.  */ +extern void __unregister_atfork (void *dso_handle) attribute_hidden; +#define UNREGISTER_ATFORK(dso_handle) __unregister_atfork (dso_handle) + + +/* C library side function to register new fork handlers.  */ +extern int __register_atfork (void (*__prepare) (void), +			      void (*__parent) (void), +			      void (*__child) (void), +			      void *dso_handle); +libc_hidden_proto (__register_atfork) + +/* Add a new element to the fork list.  */ +extern void __linkin_atfork (struct fork_handler *newp) attribute_hidden; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/getpid.c b/libpthread/nptl/sysdeps/unix/sysv/linux/getpid.c new file mode 100644 index 000000000..96e2bf439 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/getpid.c @@ -0,0 +1,64 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <unistd.h> +#include <tls.h> +#include <sysdep.h> + + +#ifndef NOT_IN_libc +static inline __attribute__((always_inline)) pid_t really_getpid (pid_t oldval); + +static inline __attribute__((always_inline)) pid_t +really_getpid (pid_t oldval) +{ +  if (__builtin_expect (oldval == 0, 1)) +    { +      pid_t selftid = THREAD_GETMEM (THREAD_SELF, tid); +      if (__builtin_expect (selftid != 0, 1)) +	return selftid; +    } + +  INTERNAL_SYSCALL_DECL (err); +  pid_t result = INTERNAL_SYSCALL (getpid, err, 0); + +  /* We do not set the PID field in the TID here since we might be +     called from a signal handler while the thread executes fork.  */ +  if (oldval == 0) +    THREAD_SETMEM (THREAD_SELF, tid, result); +  return result; +} +#endif + +pid_t +__getpid (void) +{ +#ifdef NOT_IN_libc +  INTERNAL_SYSCALL_DECL (err); +  pid_t result = INTERNAL_SYSCALL (getpid, err, 0); +#else +  pid_t result = THREAD_GETMEM (THREAD_SELF, pid); +  if (__builtin_expect (result <= 0, 0)) +    result = really_getpid (result); +#endif +  return result; +} +libc_hidden_proto(getpid) +weak_alias(__getpid, getpid) +libc_hidden_weak(getpid) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/Makefile new file mode 100644 index 000000000..43a6fad84 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../../../../ +top_builddir=../../../../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.arch +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/Makefile.arch new file mode 100644 index 000000000..570aa560e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/Makefile.arch @@ -0,0 +1,71 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# +LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/i386 +LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/i386 + +ASFLAGS += -DUSE___THREAD + +libpthread_SSRC = pt-vfork.S clone.S pthread_spin_unlock.S pthread_once.S +libpthread_CSRC = pthread_spin_init.c pt-__syscall_error.c + +libc_a_CSRC = fork.c +libc_a_SSRC = clone.S vfork.S + +libpthread_SSRC += i486/lowlevellock.S i486/pthread_barrier_wait.S i486/pthread_cond_signal.S i486/pthread_cond_broadcast.S \ +		   i486/lowlevelrobustlock.S i486/sem_post.S i486/sem_timedwait.S \ +		   i486/sem_trywait.S i486/sem_wait.S i486/pthread_rwlock_rdlock.S i486/pthread_rwlock_wrlock.S \ +		   i486/pthread_rwlock_timedrdlock.S i486/pthread_rwlock_timedwrlock.S i486/pthread_rwlock_unlock.S +#i486/pthread_cond_timedwait.S i486/pthread_cond_wait.S + +libc_a_SSRC += i486/libc-lowlevellock.S + + +CFLAGS-OMIT-fork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-pt-__syscall_error.c =  -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y) +CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__ +endif + +ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT +ASFLAGS-lowlevellock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT +ASFLAGS-lowlevelrobustlock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT +ASFLAGS-pthread_once.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT +ASFLAGS-pthread_spin_unlock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT + + +ASFLAGS-clone.S = -D_LIBC_REENTRANT +ASFLAGS-vfork.S = -D_LIBC_REENTRANT +ASFLAGS-libc-lowlevellock.S = -D_LIBC_REENTRANT + +CFLAGS += $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +LINUX_ARCH_OBJ:=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libpthread_SSRC)) +LINUX_ARCH_OBJ+=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(LINUX_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(LINUX_ARCH_OBJ) +endif +libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y+=$(LINUX_ARCH_OBJS) + +LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC)) +LIBC_LINUX_ARCH_OBJ+=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libc_a_SSRC)) + +libc-static-y+=$(LIBC_LINUX_ARCH_OBJ) +libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS) + +libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ) + +objclean-y+=nptl_linux_arch_clean + +nptl_linux_arch_clean: +	$(do_rm) $(addprefix $(LINUX_ARCH_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h new file mode 100644 index 000000000..9e3e016fb --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h @@ -0,0 +1,173 @@ +/* Copyright (C) 2002,2003,2004,2005,2006,2007 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H	1 + +#define __SIZEOF_PTHREAD_ATTR_T 36 +#define __SIZEOF_PTHREAD_MUTEX_T 24 +#define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +#define __SIZEOF_PTHREAD_COND_T 48 +#define __SIZEOF_PTHREAD_COND_COMPAT_T 12 +#define __SIZEOF_PTHREAD_CONDATTR_T 4 +#define __SIZEOF_PTHREAD_RWLOCK_T 32 +#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +#define __SIZEOF_PTHREAD_BARRIER_T 20 +#define __SIZEOF_PTHREAD_BARRIERATTR_T 4 + + +/* Thread identifiers.  The structure of the attribute type is not +   exposed on purpose.  */ +typedef unsigned long int pthread_t; + + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_ATTR_T]; +  long int __align; +} pthread_attr_t; + + +typedef struct __pthread_internal_slist +{ +  struct __pthread_internal_slist *__next; +} __pthread_slist_t; + + +/* Data structures for mutex handling.  The structure of the attribute +   type is not exposed on purpose.  */ +typedef union +{ +  struct __pthread_mutex_s +  { +    int __lock; +    unsigned int __count; +    int __owner; +    /* KIND must stay at this position in the structure to maintain +       binary compatibility.  */ +    int __kind; +    unsigned int __nusers; +    __extension__ union +    { +      int __spins; +      __pthread_slist_t __list; +    }; +  } __data; +  char __size[__SIZEOF_PTHREAD_MUTEX_T]; +  long int __align; +} pthread_mutex_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; +  long int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling.  The structure of +   the attribute type is not exposed on purpose.  */ +typedef union +{ +  struct +  { +    int __lock; +    unsigned int __futex; +    __extension__ unsigned long long int __total_seq; +    __extension__ unsigned long long int __wakeup_seq; +    __extension__ unsigned long long int __woken_seq; +    void *__mutex; +    unsigned int __nwaiters; +    unsigned int __broadcast_seq; +  } __data; +  char __size[__SIZEOF_PTHREAD_COND_T]; +  __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_CONDATTR_T]; +  long int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling.  The +   structure of the attribute type is not exposed on purpose.  */ +typedef union +{ +  struct +  { +    int __lock; +    unsigned int __nr_readers; +    unsigned int __readers_wakeup; +    unsigned int __writer_wakeup; +    unsigned int __nr_readers_queued; +    unsigned int __nr_writers_queued; +    /* FLAGS must stay at this position in the structure to maintain +       binary compatibility.  */ +    unsigned char __flags; +    unsigned char __shared; +    unsigned char __pad1; +    unsigned char __pad2; +    int __writer; +  } __data; +  char __size[__SIZEOF_PTHREAD_RWLOCK_T]; +  long int __align; +} pthread_rwlock_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; +  long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type.  */ +typedef volatile int pthread_spinlock_t; + + +/* POSIX barriers data type.  The structure of the type is +   deliberately not exposed.  */ +typedef union +{ +  char __size[__SIZEOF_PTHREAD_BARRIER_T]; +  long int __align; +} pthread_barrier_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; +  int __align; +} pthread_barrierattr_t; +#endif + + +/* Extra attributes for the cleanup functions.  */ +#define __cleanup_fct_attribute __attribute__ ((__regparm__ (1))) + +#endif	/* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/semaphore.h new file mode 100644 index 000000000..934493c30 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/semaphore.h @@ -0,0 +1,36 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + + +#define __SIZEOF_SEM_T	16 + + +/* Value returned if `sem_open' failed.  */ +#define SEM_FAILED      ((sem_t *) 0) + + +typedef union +{ +  char __size[__SIZEOF_SEM_T]; +  long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/clone.S new file mode 100644 index 000000000..9c7c46467 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/clone.S @@ -0,0 +1,2 @@ +#define RESET_PID +#include <libc/sysdeps/linux/i386/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/createthread.c new file mode 100644 index 000000000..35719be96 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/createthread.c @@ -0,0 +1,49 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +/* The "thread register" gets initialized from a segment descriptor. +   Initialize such a descriptor first.  */ +#define PREPARE_CREATE \ +  union user_desc_init desc;						      \ +									      \ +  /* Describe the thread-local storage segment.  */			      \ +									      \ +  /* The 'entry_number' field.  The first three bits of the segment	      \ +     register value select the GDT, ignore them.  We get the index	      \ +     from the value of the %gs register in the current thread.  */	      \ +  desc.vals[0] = TLS_GET_GS () >> 3;					      \ +  /* The 'base_addr' field.  Pointer to the TCB.  */			      \ +  desc.vals[1] = (unsigned long int) pd;				      \ +  /* The 'limit' field.  We use 4GB which is 0xfffff pages.  */		      \ +  desc.vals[2] = 0xfffff;						      \ +  /* Collapsed value of the bitfield:					      \ +       .seg_32bit = 1							      \ +       .contents = 0							      \ +       .read_exec_only = 0						      \ +       .limit_in_pages = 1						      \ +       .seg_not_present = 0						      \ +       .useable = 1 */							      \ +  desc.vals[3] = 0x51 + +/* Value passed to 'clone' for initialization of the thread register.  */ +#define TLS_VALUE &desc.desc + + +/* Get the real implementation.  */ +#include <sysdeps/pthread/createthread.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/fork.c new file mode 100644 index 000000000..813e5299a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/fork.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sched.h> +#include <signal.h> +#include <sysdep.h> +#include <tls.h> + + +#define ARCH_FORK() \ +  INLINE_SYSCALL (clone, 5,						      \ +		  CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0,     \ +		  NULL, NULL, &THREAD_SELF->tid) + +#include "../fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S new file mode 100644 index 000000000..ce8ad27aa --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002, 2003, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "lowlevellock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S new file mode 100644 index 000000000..00f8b56f9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S @@ -0,0 +1,459 @@ +/* Copyright (C) 2002-2004, 2006, 2007, 2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <bits/kernel-features.h> +#include <lowlevellock.h> +#include <tcb-offsets.h> + +	.text + +#ifdef __ASSUME_PRIVATE_FUTEX +# define LOAD_PRIVATE_FUTEX_WAIT(reg) \ +	movl	$(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg +# define LOAD_PRIVATE_FUTEX_WAKE(reg) \ +	movl	$(FUTEX_WAKE | FUTEX_PRIVATE_FLAG), reg +# define LOAD_FUTEX_WAIT(reg) \ +	xorl	$(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg +# define LOAD_FUTEX_WAIT_ABS(reg) \ +	xorl	$(FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME), reg +# define LOAD_FUTEX_WAKE(reg) \ +	xorl	$(FUTEX_WAKE | FUTEX_PRIVATE_FLAG), reg +#else +# if FUTEX_WAIT == 0 +#  define LOAD_PRIVATE_FUTEX_WAIT(reg) \ +	movl	%gs:PRIVATE_FUTEX, reg +# else +#  define LOAD_PRIVATE_FUTEX_WAIT(reg) \ +	movl	%gs:PRIVATE_FUTEX, reg ; \ +	orl	$FUTEX_WAIT, reg +# endif +# define LOAD_PRIVATE_FUTEX_WAKE(reg) \ +	movl	%gs:PRIVATE_FUTEX, reg ; \ +	orl	$FUTEX_WAKE, reg +# if FUTEX_WAIT == 0 +#  define LOAD_FUTEX_WAIT(reg) \ +	xorl	$FUTEX_PRIVATE_FLAG, reg ; \ +	andl	%gs:PRIVATE_FUTEX, reg +# else +#  define LOAD_FUTEX_WAIT(reg) \ +	xorl	$FUTEX_PRIVATE_FLAG, reg ; \ +	andl	%gs:PRIVATE_FUTEX, reg ; \ +	orl	$FUTEX_WAIT, reg +# endif +# define LOAD_FUTEX_WAIT_ABS(reg) \ +	xorl	$FUTEX_PRIVATE_FLAG, reg ; \ +	andl	%gs:PRIVATE_FUTEX, reg ; \ +	orl	$FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME, reg +# define LOAD_FUTEX_WAKE(reg) \ +	xorl	$FUTEX_PRIVATE_FLAG, reg ; \ +	andl	%gs:PRIVATE_FUTEX, reg ; \ +	orl	$FUTEX_WAKE, reg +#endif + +	.globl	__lll_lock_wait_private +	.type	__lll_lock_wait_private,@function +	.hidden	__lll_lock_wait_private +	.align	16 +__lll_lock_wait_private: +	cfi_startproc +	pushl	%edx +	cfi_adjust_cfa_offset(4) +	pushl	%ebx +	cfi_adjust_cfa_offset(4) +	pushl	%esi +	cfi_adjust_cfa_offset(4) +	cfi_offset(%edx, -8) +	cfi_offset(%ebx, -12) +	cfi_offset(%esi, -16) + +	movl	$2, %edx +	movl	%ecx, %ebx +	xorl	%esi, %esi	/* No timeout.  */ +	LOAD_PRIVATE_FUTEX_WAIT (%ecx) + +	cmpl	%edx, %eax	/* NB:	 %edx == 2 */ +	jne 2f + +1:	movl	$SYS_futex, %eax +	ENTER_KERNEL + +2:	movl	%edx, %eax +	xchgl	%eax, (%ebx)	/* NB:	 lock is implied */ + +	testl	%eax, %eax +	jnz	1b + +	popl	%esi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%esi) +	popl	%ebx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebx) +	popl	%edx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%edx) +	ret +	cfi_endproc +	.size	__lll_lock_wait_private,.-__lll_lock_wait_private + +#ifdef NOT_IN_libc +	.globl	__lll_lock_wait +	.type	__lll_lock_wait,@function +	.hidden	__lll_lock_wait +	.align	16 +__lll_lock_wait: +	cfi_startproc +	pushl	%edx +	cfi_adjust_cfa_offset(4) +	pushl	%ebx +	cfi_adjust_cfa_offset(4) +	pushl	%esi +	cfi_adjust_cfa_offset(4) +	cfi_offset(%edx, -8) +	cfi_offset(%ebx, -12) +	cfi_offset(%esi, -16) + +	movl	%edx, %ebx +	movl	$2, %edx +	xorl	%esi, %esi	/* No timeout.  */ +	LOAD_FUTEX_WAIT (%ecx) + +	cmpl	%edx, %eax	/* NB:	 %edx == 2 */ +	jne 2f + +1:	movl	$SYS_futex, %eax +	ENTER_KERNEL + +2:	movl	%edx, %eax +	xchgl	%eax, (%ebx)	/* NB:	 lock is implied */ + +	testl	%eax, %eax +	jnz	1b + +	popl	%esi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%esi) +	popl	%ebx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebx) +	popl	%edx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%edx) +	ret +	cfi_endproc +	.size	__lll_lock_wait,.-__lll_lock_wait + +	/*      %ecx: futex +		%esi: flags +		%edx: timeout +		%eax: futex value +	*/ +	.globl	__lll_timedlock_wait +	.type	__lll_timedlock_wait,@function +	.hidden	__lll_timedlock_wait +	.align	16 +__lll_timedlock_wait: +	cfi_startproc +	pushl	%ebp +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset(%ebp, 0) +	pushl	%ebx +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset(%ebx, 0) + +# ifndef __ASSUME_FUTEX_CLOCK_REALTIME +#  ifdef __PIC__ +	LOAD_PIC_REG (bx) +	cmpl	$0, __have_futex_clock_realtime@GOTOFF(%ebx) +#  else +	cmpl	$0, __have_futex_clock_realtime +#  endif +	je	.Lreltmo +# endif + +	movl	%ecx, %ebx +	movl	%esi, %ecx +	movl	%edx, %esi +	movl	$0xffffffff, %ebp +	LOAD_FUTEX_WAIT_ABS (%ecx) + +	movl	$2, %edx +	cmpl	%edx, %eax +	jne	2f + +1:	movl	$SYS_futex, %eax +	movl	$2, %edx +	ENTER_KERNEL + +2:	xchgl	%edx, (%ebx)	/* NB:   lock is implied */ + +	testl	%edx, %edx +	jz	3f + +	cmpl	$-ETIMEDOUT, %eax +	je	4f +	cmpl	$-EINVAL, %eax +	jne	1b +4:	movl	%eax, %edx +	negl	%edx + +3:	movl	%edx, %eax +7:	popl	%ebx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebx) +	popl	%ebp +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebp) +	ret + +# ifndef __ASSUME_FUTEX_CLOCK_REALTIME +.Lreltmo: +	/* Check for a valid timeout value.  */ +	cmpl	$1000000000, 4(%edx) +	jae	3f + +	pushl	%esi +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset(%esi, 0) +	pushl	%edi +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset(%edi, 0) + +	/* Stack frame for the timespec and timeval structs.  */ +	subl	$8, %esp +	cfi_adjust_cfa_offset(8) + +	movl	%ecx, %ebp +	movl	%edx, %edi + +	movl	$2, %edx +	xchgl	%edx, (%ebp) + +	test	%edx, %edx +	je	6f + +1: +	/* Get current time.  */ +	movl	%esp, %ebx +	xorl	%ecx, %ecx +	movl	$__NR_gettimeofday, %eax +	ENTER_KERNEL + +	/* Compute relative timeout.  */ +	movl	4(%esp), %eax +	movl	$1000, %edx +	mul	%edx		/* Milli seconds to nano seconds.  */ +	movl	(%edi), %ecx +	movl	4(%edi), %edx +	subl	(%esp), %ecx +	subl	%eax, %edx +	jns	4f +	addl	$1000000000, %edx +	subl	$1, %ecx +4:	testl	%ecx, %ecx +	js	2f		/* Time is already up.  */ + +	/* Store relative timeout.  */ +	movl	%ecx, (%esp) +	movl	%edx, 4(%esp) + +	/* Futex call.  */ +	movl	%ebp, %ebx +	movl	$2, %edx +	movl	%esp, %esi +	movl	16(%esp), %ecx +	LOAD_FUTEX_WAIT (%ecx) +	movl	$SYS_futex, %eax +	ENTER_KERNEL + +	/* NB: %edx == 2 */ +	xchgl	%edx, (%ebp) + +	testl	%edx, %edx +	je	6f + +	cmpl	$-ETIMEDOUT, %eax +	jne	1b +2:	movl	$ETIMEDOUT, %edx + +6:	addl	$8, %esp +	cfi_adjust_cfa_offset(-8) +	popl	%edi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%edi) +	popl	%esi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%esi) +7:	popl	%ebx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebx) +	popl	%ebp +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebp) +	movl	%edx, %eax +	ret + +3:	movl	$EINVAL, %edx +	jmp	7b +# endif +	cfi_endproc +	.size	__lll_timedlock_wait,.-__lll_timedlock_wait +#endif + +	.globl	__lll_unlock_wake_private +	.type	__lll_unlock_wake_private,@function +	.hidden	__lll_unlock_wake_private +	.align	16 +__lll_unlock_wake_private: +	cfi_startproc +	pushl	%ebx +	cfi_adjust_cfa_offset(4) +	pushl	%ecx +	cfi_adjust_cfa_offset(4) +	pushl	%edx +	cfi_adjust_cfa_offset(4) +	cfi_offset(%ebx, -8) +	cfi_offset(%ecx, -12) +	cfi_offset(%edx, -16) + +	movl	%eax, %ebx +	movl	$0, (%eax) +	LOAD_PRIVATE_FUTEX_WAKE (%ecx) +	movl	$1, %edx	/* Wake one thread.  */ +	movl	$SYS_futex, %eax +	ENTER_KERNEL + +	popl	%edx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%edx) +	popl	%ecx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ecx) +	popl	%ebx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebx) +	ret +	cfi_endproc +	.size	__lll_unlock_wake_private,.-__lll_unlock_wake_private + +#ifdef NOT_IN_libc +	.globl	__lll_unlock_wake +	.type	__lll_unlock_wake,@function +	.hidden	__lll_unlock_wake +	.align	16 +__lll_unlock_wake: +	cfi_startproc +	pushl	%ebx +	cfi_adjust_cfa_offset(4) +	pushl	%ecx +	cfi_adjust_cfa_offset(4) +	pushl	%edx +	cfi_adjust_cfa_offset(4) +	cfi_offset(%ebx, -8) +	cfi_offset(%ecx, -12) +	cfi_offset(%edx, -16) + +	movl	%eax, %ebx +	movl	$0, (%eax) +	LOAD_FUTEX_WAKE (%ecx) +	movl	$1, %edx	/* Wake one thread.  */ +	movl	$SYS_futex, %eax +	ENTER_KERNEL + +	popl	%edx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%edx) +	popl	%ecx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ecx) +	popl	%ebx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebx) +	ret +	cfi_endproc +	.size	__lll_unlock_wake,.-__lll_unlock_wake + +	.globl	__lll_timedwait_tid +	.type	__lll_timedwait_tid,@function +	.hidden	__lll_timedwait_tid +	.align	16 +__lll_timedwait_tid: +	pushl	%edi +	pushl	%esi +	pushl	%ebx +	pushl	%ebp + +	movl	%eax, %ebp +	movl	%edx, %edi +	subl	$8, %esp + +	/* Get current time.  */ +2:	movl	%esp, %ebx +	xorl	%ecx, %ecx +	movl	$__NR_gettimeofday, %eax +	ENTER_KERNEL + +	/* Compute relative timeout.  */ +	movl	4(%esp), %eax +	movl	$1000, %edx +	mul	%edx		/* Milli seconds to nano seconds.  */ +	movl	(%edi), %ecx +	movl	4(%edi), %edx +	subl	(%esp), %ecx +	subl	%eax, %edx +	jns	5f +	addl	$1000000000, %edx +	subl	$1, %ecx +5:	testl	%ecx, %ecx +	js	6f		/* Time is already up.  */ + +	movl	%ecx, (%esp)	/* Store relative timeout.  */ +	movl	%edx, 4(%esp) + +	movl	(%ebp), %edx +	testl	%edx, %edx +	jz	4f + +	movl	%esp, %esi +	/* XXX The kernel so far uses global futex for the wakeup at +	   all times.  */ +	xorl	%ecx, %ecx	/* movl $FUTEX_WAIT, %ecx */ +	movl	%ebp, %ebx +	movl	$SYS_futex, %eax +	ENTER_KERNEL + +	cmpl	$0, (%ebx) +	jne	1f +4:	xorl	%eax, %eax + +3:	addl	$8, %esp +	popl	%ebp +	popl	%ebx +	popl	%esi +	popl	%edi +	ret + +1:	cmpl	$-ETIMEDOUT, %eax +	jne	2b +6:	movl	$ETIMEDOUT, %eax +	jmp	3b +	.size	__lll_timedwait_tid,.-__lll_timedwait_tid +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelrobustlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelrobustlock.S new file mode 100644 index 000000000..1d038001c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelrobustlock.S @@ -0,0 +1,234 @@ +/* Copyright (C) 2002, 2003, 2004, 2006, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <lowlevellock.h> +#include <lowlevelrobustlock.h> +#include <bits/kernel-features.h> +#include <tls.h> + +	.text + +#define FUTEX_WAITERS		0x80000000 +#define FUTEX_OWNER_DIED	0x40000000 + +#ifdef __ASSUME_PRIVATE_FUTEX +# define LOAD_FUTEX_WAIT(reg) \ +	xorl	$(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg +#else +# if FUTEX_WAIT == 0 +#  define LOAD_FUTEX_WAIT(reg) \ +	xorl	$FUTEX_PRIVATE_FLAG, reg ; \ +	andl	%gs:PRIVATE_FUTEX, reg +# else +#  define LOAD_FUTEX_WAIT(reg) \ +	xorl	$FUTEX_PRIVATE_FLAG, reg ; \ +	andl	%gs:PRIVATE_FUTEX, reg ; \ +	orl	$FUTEX_WAIT, reg +# endif +#endif + +	.globl	__lll_robust_lock_wait +	.type	__lll_robust_lock_wait,@function +	.hidden	__lll_robust_lock_wait +	.align	16 +__lll_robust_lock_wait: +	cfi_startproc +	pushl	%edx +	cfi_adjust_cfa_offset(4) +	pushl	%ebx +	cfi_adjust_cfa_offset(4) +	pushl	%esi +	cfi_adjust_cfa_offset(4) +	cfi_offset(%edx, -8) +	cfi_offset(%ebx, -12) +	cfi_offset(%esi, -16) + +	movl	%edx, %ebx +	xorl	%esi, %esi	/* No timeout.  */ +	LOAD_FUTEX_WAIT (%ecx) + +4:	movl	%eax, %edx +	orl	$FUTEX_WAITERS, %edx + +	testl	$FUTEX_OWNER_DIED, %eax +	jnz	3f + +	cmpl	%edx, %eax	/* NB:	 %edx == 2 */ +	je	1f + +	LOCK +	cmpxchgl %edx, (%ebx) +	jnz	2f + +1:	movl	$SYS_futex, %eax +	ENTER_KERNEL + +	movl	(%ebx), %eax + +2:	test	%eax, %eax +	jne	4b + +	movl	%gs:TID, %edx +	orl	$FUTEX_WAITERS, %edx +	LOCK +	cmpxchgl %edx, (%ebx) +	jnz	4b +	/* NB:	 %eax == 0 */ + +3:	popl	%esi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%esi) +	popl	%ebx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebx) +	popl	%edx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%edx) +	ret +	cfi_endproc +	.size	__lll_robust_lock_wait,.-__lll_robust_lock_wait + + +	.globl	__lll_robust_timedlock_wait +	.type	__lll_robust_timedlock_wait,@function +	.hidden	__lll_robust_timedlock_wait +	.align	16 +__lll_robust_timedlock_wait: +	cfi_startproc +	/* Check for a valid timeout value.  */ +	cmpl	$1000000000, 4(%edx) +	jae	3f + +	pushl	%edi +	cfi_adjust_cfa_offset(4) +	pushl	%esi +	cfi_adjust_cfa_offset(4) +	pushl	%ebx +	cfi_adjust_cfa_offset(4) +	pushl	%ebp +	cfi_adjust_cfa_offset(4) +	cfi_offset(%edi, -8) +	cfi_offset(%esi, -12) +	cfi_offset(%ebx, -16) +	cfi_offset(%ebp, -20) + +	/* Stack frame for the timespec and timeval structs.  */ +	subl	$12, %esp +	cfi_adjust_cfa_offset(12) + +	movl	%ecx, %ebp +	movl	%edx, %edi + +1:	movl	%eax, 8(%esp) + +	/* Get current time.  */ +	movl	%esp, %ebx +	xorl	%ecx, %ecx +	movl	$__NR_gettimeofday, %eax +	ENTER_KERNEL + +	/* Compute relative timeout.  */ +	movl	4(%esp), %eax +	movl	$1000, %edx +	mul	%edx		/* Milli seconds to nano seconds.  */ +	movl	(%edi), %ecx +	movl	4(%edi), %edx +	subl	(%esp), %ecx +	subl	%eax, %edx +	jns	4f +	addl	$1000000000, %edx +	subl	$1, %ecx +4:	testl	%ecx, %ecx +	js	8f		/* Time is already up.  */ + +	/* Store relative timeout.  */ +	movl	%ecx, (%esp) +	movl	%edx, 4(%esp) + +	movl	%ebp, %ebx + +	movl	8(%esp), %edx +	movl	%edx, %eax +	orl	$FUTEX_WAITERS, %edx + +	testl	$FUTEX_OWNER_DIED, %eax +	jnz	6f + +	cmpl	%eax, %edx +	je	2f + +	LOCK +	cmpxchgl %edx, (%ebx) +	movl	$0, %ecx	/* Must use mov to avoid changing cc.  */ +	jnz	5f + +2: +	/* Futex call.  */ +	movl	%esp, %esi +	movl	20(%esp), %ecx +	LOAD_FUTEX_WAIT (%ecx) +	movl	$SYS_futex, %eax +	ENTER_KERNEL +	movl	%eax, %ecx + +	movl	(%ebx), %eax + +5:	testl	%eax, %eax +	jne	7f + +	movl	%gs:TID, %edx +	orl	$FUTEX_WAITERS, %edx +	LOCK +	cmpxchgl %edx, (%ebx) +	jnz	7f + +6:	addl	$12, %esp +	cfi_adjust_cfa_offset(-12) +	popl	%ebp +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebp) +	popl	%ebx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebx) +	popl	%esi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%esi) +	popl	%edi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%edi) +	ret + +3:	movl	$EINVAL, %eax +	ret + +	cfi_adjust_cfa_offset(28) +	cfi_offset(%edi, -8) +	cfi_offset(%esi, -12) +	cfi_offset(%ebx, -16) +	cfi_offset(%ebp, -20) +	/* Check whether the time expired.  */ +7:	cmpl	$-ETIMEDOUT, %ecx +	jne	1b + +8:	movl	$ETIMEDOUT, %eax +	jmp	6b +	cfi_endproc +	.size	__lll_robust_timedlock_wait,.-__lll_robust_timedlock_wait diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S new file mode 100644 index 000000000..040d7f8c3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S @@ -0,0 +1,187 @@ +/* Copyright (C) 2002, 2003, 2004, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelbarrier.h> + +	.text + +	.globl	pthread_barrier_wait +	.type	pthread_barrier_wait,@function +	.align	16 +pthread_barrier_wait: +	cfi_startproc +	pushl	%ebx +	cfi_adjust_cfa_offset(4) +	cfi_offset(%ebx, -8) + +	movl	8(%esp), %ebx + +	/* Get the mutex.  */ +	movl	$1, %edx +	xorl	%eax, %eax +	LOCK +	cmpxchgl %edx, MUTEX(%ebx) +	jnz	1f + +	/* One less waiter.  If this was the last one needed wake +	   everybody.  */ +2:	subl	$1, LEFT(%ebx) +	je	3f + +	/* There are more threads to come.  */ +	pushl	%esi +	cfi_adjust_cfa_offset(4) +	cfi_offset(%esi, -12) + +#if CURR_EVENT == 0 +	movl	(%ebx), %edx +#else +	movl	CURR_EVENT(%ebx), %edx +#endif + +	/* Release the mutex.  */ +	LOCK +	subl	$1, MUTEX(%ebx) +	jne	6f + +	/* Wait for the remaining threads.  The call will return immediately +	   if the CURR_EVENT memory has meanwhile been changed.  */ +7: +#if FUTEX_WAIT == 0 +	movl	PRIVATE(%ebx), %ecx +#else +	movl	$FUTEX_WAIT, %ecx +	orl	PRIVATE(%ebx), %ecx +#endif +	xorl	%esi, %esi +8:	movl	$SYS_futex, %eax +	ENTER_KERNEL + +	/* Don't return on spurious wakeups.  The syscall does not change +	   any register except %eax so there is no need to reload any of +	   them.  */ +#if CURR_EVENT == 0 +	cmpl	%edx, (%ebx) +#else +	cmpl	%edx, CURR_EVENT(%ebx) +#endif +	je	8b + +	/* Increment LEFT.  If this brings the count back to the +	   initial count unlock the object.  */ +	movl	$1, %edx +	movl	INIT_COUNT(%ebx), %ecx +	LOCK +	xaddl	%edx, LEFT(%ebx) +	subl	$1, %ecx +	cmpl	%ecx, %edx +	jne	10f + +	/* Release the mutex.  We cannot release the lock before +	   waking the waiting threads since otherwise a new thread might +	   arrive and gets waken up, too.  */ +	LOCK +	subl	$1, MUTEX(%ebx) +	jne	9f + +	/* Note: %esi is still zero.  */ +10:	movl	%esi, %eax		/* != PTHREAD_BARRIER_SERIAL_THREAD */ + +	popl	%esi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%esi) +	popl	%ebx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebx) +	ret + +	cfi_adjust_cfa_offset(4) +	cfi_offset(%ebx, -8) +	 +	/* The necessary number of threads arrived.  */ +3: +#if CURR_EVENT == 0 +	addl	$1, (%ebx) +#else +	addl	$1, CURR_EVENT(%ebx) +#endif + +	/* Wake up all waiters.  The count is a signed number in the kernel +	   so 0x7fffffff is the highest value.  */ +	movl	$0x7fffffff, %edx +	movl	$FUTEX_WAKE, %ecx +	orl	PRIVATE(%ebx), %ecx +	movl	$SYS_futex, %eax +	ENTER_KERNEL + +	/* Increment LEFT.  If this brings the count back to the +	   initial count unlock the object.  */ +	movl	$1, %edx +	movl	INIT_COUNT(%ebx), %ecx +	LOCK +	xaddl	%edx, LEFT(%ebx) +	subl	$1, %ecx +	cmpl	%ecx, %edx +	jne	5f + +	/* Release the mutex.  We cannot release the lock before +	   waking the waiting threads since otherwise a new thread might +	   arrive and gets waken up, too.  */ +	LOCK +	subl	$1, MUTEX(%ebx) +	jne	4f + +5:	orl	$-1, %eax		/* == PTHREAD_BARRIER_SERIAL_THREAD */ + +	popl	%ebx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebx) +	ret + +	cfi_adjust_cfa_offset(4) +	cfi_offset(%ebx, -8) +1:	movl	PRIVATE(%ebx), %ecx +	leal	MUTEX(%ebx), %edx +	xorl	$LLL_SHARED, %ecx +	call	__lll_lock_wait +	jmp	2b + +4:	movl	PRIVATE(%ebx), %ecx +	leal	MUTEX(%ebx), %eax +	xorl	$LLL_SHARED, %ecx +	call	__lll_unlock_wake +	jmp	5b + +	cfi_adjust_cfa_offset(4) +	cfi_offset(%esi, -12) +6:	movl	PRIVATE(%ebx), %ecx +	leal	MUTEX(%ebx), %eax +	xorl	$LLL_SHARED, %ecx +	call	__lll_unlock_wake +	jmp	7b + +9:	movl	PRIVATE(%ebx), %ecx +	leal	MUTEX(%ebx), %eax +	xorl	$LLL_SHARED, %ecx +	call	__lll_unlock_wake +	jmp	10b +	cfi_endproc +	.size	pthread_barrier_wait,.-pthread_barrier_wait diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S new file mode 100644 index 000000000..ca9ceca00 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S @@ -0,0 +1,239 @@ +/* Copyright (C) 2002,2003,2004,2006,2007,2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelcond.h> +#include <bits/kernel-features.h> +#include <pthread-pi-defines.h> +#include <pthread-errnos.h> +#include <tls.h> + +	.text + +	/* int pthread_cond_broadcast (pthread_cond_t *cond) */ +	.globl	__pthread_cond_broadcast +	.type	__pthread_cond_broadcast, @function +	.protected	__pthread_cond_broadcast +	.align	16 +__pthread_cond_broadcast: +	cfi_startproc +	pushl	%ebx +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset(%ebx, 0) +	pushl	%esi +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset(%esi, 0) +	pushl	%edi +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset(%edi, 0) +	pushl	%ebp +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset(%ebp, 0) +	cfi_remember_state + +	movl	20(%esp), %ebx + +	/* Get internal lock.  */ +	movl	$1, %edx +	xorl	%eax, %eax +	LOCK +#if cond_lock == 0 +	cmpxchgl %edx, (%ebx) +#else +	cmpxchgl %edx, cond_lock(%ebx) +#endif +	jnz	1f + +2:	addl	$cond_futex, %ebx +	movl	total_seq+4-cond_futex(%ebx), %eax +	movl	total_seq-cond_futex(%ebx), %ebp +	cmpl	wakeup_seq+4-cond_futex(%ebx), %eax +	ja	3f +	jb	4f +	cmpl	wakeup_seq-cond_futex(%ebx), %ebp +	jna	4f + +	/* Cause all currently waiting threads to recognize they are +	   woken up.  */ +3:	movl	%ebp, wakeup_seq-cond_futex(%ebx) +	movl	%eax, wakeup_seq-cond_futex+4(%ebx) +	movl	%ebp, woken_seq-cond_futex(%ebx) +	movl	%eax, woken_seq-cond_futex+4(%ebx) +	addl	%ebp, %ebp +	addl	$1, broadcast_seq-cond_futex(%ebx) +	movl	%ebp, (%ebx) + +	/* Get the address of the mutex used.  */ +	movl	dep_mutex-cond_futex(%ebx), %edi + +	/* Unlock.  */ +	LOCK +	subl	$1, cond_lock-cond_futex(%ebx) +	jne	7f + +	/* Don't use requeue for pshared condvars.  */ +8:	cmpl	$-1, %edi +	je	9f + +	/* Do not use requeue for pshared condvars.  */ +	testl	$PS_BIT, MUTEX_KIND(%edi) +	jne	9f + +	/* Requeue to a non-robust PI mutex if the PI bit is set and +	   the robust bit is not set.  */ +	movl	MUTEX_KIND(%edi), %eax +	andl	$(ROBUST_BIT|PI_BIT), %eax +	cmpl	$PI_BIT, %eax +	je	81f + +	/* Wake up all threads.  */ +#ifdef __ASSUME_PRIVATE_FUTEX +	movl	$(FUTEX_CMP_REQUEUE|FUTEX_PRIVATE_FLAG), %ecx +#else +	movl	%gs:PRIVATE_FUTEX, %ecx +	orl	$FUTEX_CMP_REQUEUE, %ecx +#endif +	movl	$SYS_futex, %eax +	movl	$0x7fffffff, %esi +	movl	$1, %edx +	/* Get the address of the futex involved.  */ +# if MUTEX_FUTEX != 0 +	addl	$MUTEX_FUTEX, %edi +# endif +/* FIXME: Until Ingo fixes 4G/4G vDSO, 6 arg syscalls are broken for sysenter. +	ENTER_KERNEL  */ +	int	$0x80 + +	/* For any kind of error, which mainly is EAGAIN, we try again +	   with WAKE.  The general test also covers running on old +	   kernels.  */ +	cmpl	$0xfffff001, %eax +	jae	9f + +6:	xorl	%eax, %eax +	popl	%ebp +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebp) +	popl	%edi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%edi) +	popl	%esi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%esi) +	popl	%ebx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebx) +	ret + +	cfi_restore_state + +81:	movl	$(FUTEX_CMP_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %ecx +	movl	$SYS_futex, %eax +	movl	$0x7fffffff, %esi +	movl	$1, %edx +	/* Get the address of the futex involved.  */ +# if MUTEX_FUTEX != 0 +	addl	$MUTEX_FUTEX, %edi +# endif +	int	$0x80 + +	/* For any kind of error, which mainly is EAGAIN, we try again +	with WAKE.  The general test also covers running on old +	kernels.  */ +	cmpl	$0xfffff001, %eax +	jb	6b +	jmp	9f + +	/* Initial locking failed.  */ +1: +#if cond_lock == 0 +	movl	%ebx, %edx +#else +	leal	cond_lock(%ebx), %edx +#endif +#if (LLL_SHARED-LLL_PRIVATE) > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex(%ebx) +	setne	%cl +	subl	$1, %ecx +	andl	$(LLL_SHARED-LLL_PRIVATE), %ecx +#if LLL_PRIVATE != 0 +	addl	$LLL_PRIVATE, %ecx +#endif +	call	__lll_lock_wait +	jmp	2b + +	.align	16 +	/* Unlock.  */ +4:	LOCK +	subl	$1, cond_lock-cond_futex(%ebx) +	je	6b + +	/* Unlock in loop requires wakeup.  */ +5:	leal	cond_lock-cond_futex(%ebx), %eax +#if (LLL_SHARED-LLL_PRIVATE) > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex-cond_futex(%ebx) +	setne	%cl +	subl	$1, %ecx +	andl	$(LLL_SHARED-LLL_PRIVATE), %ecx +#if LLL_PRIVATE != 0 +	addl	$LLL_PRIVATE, %ecx +#endif +	call	__lll_unlock_wake +	jmp	6b + +	/* Unlock in loop requires wakeup.  */ +7:	leal	cond_lock-cond_futex(%ebx), %eax +#if (LLL_SHARED-LLL_PRIVATE) > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex-cond_futex(%ebx) +	setne	%cl +	subl	$1, %ecx +	andl	$(LLL_SHARED-LLL_PRIVATE), %ecx +#if LLL_PRIVATE != 0 +	addl	$LLL_PRIVATE, %ecx +#endif +	call	__lll_unlock_wake +	jmp	8b + +9:	/* The futex requeue functionality is not available.  */ +	movl	$0x7fffffff, %edx +#if FUTEX_PRIVATE_FLAG > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex-cond_futex(%ebx) +	sete	%cl +	subl	$1, %ecx +#ifdef __ASSUME_PRIVATE_FUTEX +	andl	$FUTEX_PRIVATE_FLAG, %ecx +#else +	andl	%gs:PRIVATE_FUTEX, %ecx +#endif +	addl	$FUTEX_WAKE, %ecx +	movl	$SYS_futex, %eax +	ENTER_KERNEL +	jmp	6b +	cfi_endproc +	.size	__pthread_cond_broadcast, .-__pthread_cond_broadcast +weak_alias(__pthread_cond_broadcast, pthread_cond_broadcast) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S new file mode 100644 index 000000000..118bc073b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S @@ -0,0 +1,216 @@ +/* Copyright (C) 2002,2003,2004,2005,2007,2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelcond.h> +#include <bits/kernel-features.h> +#include <pthread-pi-defines.h> +#include <pthread-errnos.h> +#include <tls.h> + + +	.text + +	/* int pthread_cond_signal (pthread_cond_t *cond) */ +	.globl	__pthread_cond_signal +	.type	__pthread_cond_signal, @function +	.protected	__pthread_cond_signal +	.align	16 +__pthread_cond_signal: + +	cfi_startproc +	pushl	%ebx +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset(%ebx, 0) +	pushl	%edi +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset(%edi, 0) +	cfi_remember_state + +	movl	12(%esp), %edi + +	/* Get internal lock.  */ +	movl	$1, %edx +	xorl	%eax, %eax +	LOCK +#if cond_lock == 0 +	cmpxchgl %edx, (%edi) +#else +	cmpxchgl %edx, cond_lock(%edi) +#endif +	jnz	1f + +2:	leal	cond_futex(%edi), %ebx +	movl	total_seq+4(%edi), %eax +	movl	total_seq(%edi), %ecx +	cmpl	wakeup_seq+4(%edi), %eax +#if cond_lock != 0 +	/* Must use leal to preserve the flags.  */ +	leal	cond_lock(%edi), %edi +#endif +	ja	3f +	jb	4f +	cmpl	wakeup_seq-cond_futex(%ebx), %ecx +	jbe	4f + +	/* Bump the wakeup number.  */ +3:	addl	$1, wakeup_seq-cond_futex(%ebx) +	adcl	$0, wakeup_seq-cond_futex+4(%ebx) +	addl	$1, (%ebx) + +	/* Wake up one thread.  */ +	pushl	%esi +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset(%esi, 0) +	pushl	%ebp +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset(%ebp, 0) + +#if FUTEX_PRIVATE_FLAG > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex-cond_futex(%ebx) +	sete	%cl +	je	8f + +	movl	dep_mutex-cond_futex(%ebx), %edx +	/* Requeue to a non-robust PI mutex if the PI bit is set and +	   the robust bit is not set.  */ +	movl	MUTEX_KIND(%edx), %eax +	andl	$(ROBUST_BIT|PI_BIT), %eax +	cmpl	$PI_BIT, %eax +	je	9f + +8:	subl	$1, %ecx +#ifdef __ASSUME_PRIVATE_FUTEX +	andl	$FUTEX_PRIVATE_FLAG, %ecx +#else +	andl	%gs:PRIVATE_FUTEX, %ecx +#endif +	addl	$FUTEX_WAKE_OP, %ecx +	movl	$SYS_futex, %eax +	movl	$1, %edx +	movl	$1, %esi +	movl	$FUTEX_OP_CLEAR_WAKE_IF_GT_ONE, %ebp +	/* FIXME: Until Ingo fixes 4G/4G vDSO, 6 arg syscalls are broken for +	   sysenter. +	ENTER_KERNEL  */ +	int	$0x80 +	popl	%ebp +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebp) +	popl	%esi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%esi) + +	/* For any kind of error, we try again with WAKE. +	   The general test also covers running on old kernels.  */ +	cmpl	$-4095, %eax +	jae	7f + +6:	xorl	%eax, %eax +	popl	%edi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%edi) +	popl	%ebx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebx) +	ret + +	cfi_restore_state + +9:	movl	$(FUTEX_CMP_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %ecx +	movl	$SYS_futex, %eax +	movl	$1, %edx +	xorl	%esi, %esi +	movl	dep_mutex-cond_futex(%ebx), %edi +	movl	(%ebx), %ebp +	/* FIXME: Until Ingo fixes 4G/4G vDSO, 6 arg syscalls are broken for +	   sysenter. +	ENTER_KERNEL  */ +	int	$0x80 +	popl	%ebp +	popl	%esi + +	leal	-cond_futex(%ebx), %edi + +	/* For any kind of error, we try again with WAKE. +	   The general test also covers running on old kernels.  */ +	cmpl	$-4095, %eax +	jb	4f + +7: +#ifdef __ASSUME_PRIVATE_FUTEX +	andl	$FUTEX_PRIVATE_FLAG, %ecx +#else +	andl	%gs:PRIVATE_FUTEX, %ecx +#endif +	orl	$FUTEX_WAKE, %ecx + +	xorl	$(FUTEX_WAKE ^ FUTEX_WAKE_OP), %ecx +	movl	$SYS_futex, %eax +	/* %edx should be 1 already from $FUTEX_WAKE_OP syscall. +	movl	$1, %edx  */ +	ENTER_KERNEL + +	/* Unlock.  Note that at this point %edi always points to +	   cond_lock.  */ +4:	LOCK +	subl	$1, (%edi) +	je	6b + +	/* Unlock in loop requires wakeup.  */ +5:	movl	%edi, %eax +#if (LLL_SHARED-LLL_PRIVATE) > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex-cond_futex(%ebx) +	setne	%cl +	subl	$1, %ecx +	andl	$(LLL_SHARED-LLL_PRIVATE), %ecx +#if LLL_PRIVATE != 0 +	addl	$LLL_PRIVATE, %ecx +#endif +	call	__lll_unlock_wake +	jmp	6b + +	/* Initial locking failed.  */ +1: +#if cond_lock == 0 +	movl	%edi, %edx +#else +	leal	cond_lock(%edi), %edx +#endif +#if (LLL_SHARED-LLL_PRIVATE) > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex(%edi) +	setne	%cl +	subl	$1, %ecx +	andl	$(LLL_SHARED-LLL_PRIVATE), %ecx +#if LLL_PRIVATE != 0 +	addl	$LLL_PRIVATE, %ecx +#endif +	call	__lll_lock_wait +	jmp	2b + +	cfi_endproc +	.size	__pthread_cond_signal, .-__pthread_cond_signal +weak_alias(__pthread_cond_signal, pthread_cond_signal) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S new file mode 100644 index 000000000..8a0c3fbf6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S @@ -0,0 +1,694 @@ +/* Copyright (C) 2002-2004,2006-2007,2009,2010 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelcond.h> +#include <pthread-errnos.h> +#include <pthread-pi-defines.h> +#include <bits/kernel-features.h> + + +	.text + +/* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, +			       const struct timespec *abstime)  */ +	.globl	__pthread_cond_timedwait +	.type	__pthread_cond_timedwait, @function +	.protected	__pthread_cond_timedwait +	.align	16 +__pthread_cond_timedwait: +.LSTARTCODE: +	cfi_startproc +#ifdef SHARED +	cfi_personality(DW_EH_PE_pcrel | DW_EH_PE_sdata4 | DW_EH_PE_indirect, +			DW.ref.__gcc_personality_v0) +	cfi_lsda(DW_EH_PE_pcrel | DW_EH_PE_sdata4, .LexceptSTART) +#else +	cfi_personality(DW_EH_PE_udata4, __gcc_personality_v0) +	cfi_lsda(DW_EH_PE_udata4, .LexceptSTART) +#endif + +	pushl	%ebp +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset(%ebp, 0) +	pushl	%edi +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset(%edi, 0) +	pushl	%esi +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset(%esi, 0) +	pushl	%ebx +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset(%ebx, 0) + +	movl	20(%esp), %ebx +	movl	28(%esp), %ebp + +	cmpl	$1000000000, 4(%ebp) +	movl	$EINVAL, %eax +	jae	18f + +	/* Get internal lock.  */ +	movl	$1, %edx +	xorl	%eax, %eax +	LOCK +#if cond_lock == 0 +	cmpxchgl %edx, (%ebx) +#else +	cmpxchgl %edx, cond_lock(%ebx) +#endif +	jnz	1f + +	/* Store the reference to the mutex.  If there is already a +	   different value in there this is a bad user bug.  */ +2:	cmpl	$-1, dep_mutex(%ebx) +	movl	24(%esp), %eax +	je	17f +	movl	%eax, dep_mutex(%ebx) + +	/* Unlock the mutex.  */ +17:	xorl	%edx, %edx +	call	__pthread_mutex_unlock_usercnt + +	testl	%eax, %eax +	jne	16f + +	addl	$1, total_seq(%ebx) +	adcl	$0, total_seq+4(%ebx) +	addl	$1, cond_futex(%ebx) +	addl	$(1 << nwaiters_shift), cond_nwaiters(%ebx) + +#define FRAME_SIZE 32 +	subl	$FRAME_SIZE, %esp +	cfi_adjust_cfa_offset(FRAME_SIZE) +	cfi_remember_state + +	/* Get and store current wakeup_seq value.  */ +	movl	wakeup_seq(%ebx), %edi +	movl	wakeup_seq+4(%ebx), %edx +	movl	broadcast_seq(%ebx), %eax +	movl	%edi, 12(%esp) +	movl	%edx, 16(%esp) +	movl	%eax, 20(%esp) + +	/* Reset the pi-requeued flag.  */ +8:	movl	$0, 24(%esp) +	/* Get the current time.  */ +	movl	%ebx, %edx +#ifdef __NR_clock_gettime +	/* Get the clock number.  */ +	movl	cond_nwaiters(%ebx), %ebx +	andl	$((1 << nwaiters_shift) - 1), %ebx +	/* Only clocks 0 and 1 are allowed so far.  Both are handled in the +	   kernel.  */ +	leal	4(%esp), %ecx +	movl	$__NR_clock_gettime, %eax +	ENTER_KERNEL +# ifndef __ASSUME_POSIX_TIMERS +	cmpl	$-ENOSYS, %eax +	je	19f +# endif +	movl	%edx, %ebx + +	/* Compute relative timeout.  */ +	movl	(%ebp), %ecx +	movl	4(%ebp), %edx +	subl	4(%esp), %ecx +	subl	8(%esp), %edx +#else +	/* Get the current time.  */ +	leal	4(%esp), %ebx +	xorl	%ecx, %ecx +	movl	$__NR_gettimeofday, %eax +	ENTER_KERNEL +	movl	%edx, %ebx + +	/* Compute relative timeout.  */ +	movl	8(%esp), %eax +	movl	$1000, %edx +	mul	%edx		/* Milli seconds to nano seconds.  */ +	movl	(%ebp), %ecx +	movl	4(%ebp), %edx +	subl	4(%esp), %ecx +	subl	%eax, %edx +#endif +	jns	12f +	addl	$1000000000, %edx +	subl	$1, %ecx +12:	testl	%ecx, %ecx +	movl	$-ETIMEDOUT, %esi +	js	6f + +	/* Store relative timeout.  */ +21:	movl	%ecx, 4(%esp) +	movl	%edx, 8(%esp) + +	movl	cond_futex(%ebx), %edi +	movl	%edi, 28(%esp) + +	/* Unlock.  */ +	LOCK +#if cond_lock == 0 +	subl	$1, (%ebx) +#else +	subl	$1, cond_lock(%ebx) +#endif +	jne	3f + +.LcleanupSTART: +4:	call	__pthread_enable_asynccancel +	movl	%eax, (%esp) + +#if FUTEX_PRIVATE_FLAG > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex(%ebx) +	sete	%cl +	je	40f + +	movl	dep_mutex(%ebx), %edi +	/* Requeue to a non-robust PI mutex if the PI bit is set and +	   the robust bit is not set.  */ +	movl	MUTEX_KIND(%edi), %eax +	andl	$(ROBUST_BIT|PI_BIT), %eax +	cmpl	$PI_BIT, %eax +	jne	40f + +	movl	$(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %ecx +	/* The following only works like this because we only support +	   two clocks, represented using a single bit.  */ +	testl	$1, cond_nwaiters(%ebx) +	/* XXX Need to implement using sete instead of a jump.  */ +	jne	42f +	orl	$FUTEX_CLOCK_REALTIME, %ecx + +	/* Requeue-PI uses absolute timeout */ +42:	leal	(%ebp), %esi +	movl	28(%esp), %edx +	addl	$cond_futex, %ebx +	movl	$SYS_futex, %eax +	ENTER_KERNEL +	subl	$cond_futex, %ebx +	movl	%eax, %esi +	/* Set the pi-requeued flag only if the kernel has returned 0. The +	   kernel does not hold the mutex on ETIMEDOUT or any other error.  */ +	cmpl	$0, %eax +	sete	24(%esp) +	je	41f + +	/* Normal and PI futexes dont mix. Use normal futex functions only +	   if the kernel does not support the PI futex functions.  */ +	cmpl	$-ENOSYS, %eax +	jne	41f +	xorl	%ecx, %ecx + +40:	subl	$1, %ecx +#ifdef __ASSUME_PRIVATE_FUTEX +	andl	$FUTEX_PRIVATE_FLAG, %ecx +#else +	andl	%gs:PRIVATE_FUTEX, %ecx +#endif +#if FUTEX_WAIT != 0 +	addl	$FUTEX_WAIT, %ecx +#endif +	leal	4(%esp), %esi +	movl	28(%esp), %edx +	addl	$cond_futex, %ebx +.Ladd_cond_futex: +	movl	$SYS_futex, %eax +	ENTER_KERNEL +	subl	$cond_futex, %ebx +.Lsub_cond_futex: +	movl	%eax, %esi + +41:	movl	(%esp), %eax +	call	__pthread_disable_asynccancel +.LcleanupEND: + +	/* Lock.  */ +	movl	$1, %edx +	xorl	%eax, %eax +	LOCK +#if cond_lock == 0 +	cmpxchgl %edx, (%ebx) +#else +	cmpxchgl %edx, cond_lock(%ebx) +#endif +	jnz	5f + +6:	movl	broadcast_seq(%ebx), %eax +	cmpl	20(%esp), %eax +	jne	23f + +	movl	woken_seq(%ebx), %eax +	movl	woken_seq+4(%ebx), %ecx + +	movl	wakeup_seq(%ebx), %edi +	movl	wakeup_seq+4(%ebx), %edx + +	cmpl	16(%esp), %edx +	jne	7f +	cmpl	12(%esp), %edi +	je	15f + +7:	cmpl	%ecx, %edx +	jne	9f +	cmp	%eax, %edi +	jne	9f + +15:	cmpl	$-ETIMEDOUT, %esi +	jne	8b + +	addl	$1, wakeup_seq(%ebx) +	adcl	$0, wakeup_seq+4(%ebx) +	addl	$1, cond_futex(%ebx) +	movl	$ETIMEDOUT, %esi +	jmp	14f + +23:	xorl	%esi, %esi +	jmp	24f + +9:	xorl	%esi, %esi +14:	addl	$1, woken_seq(%ebx) +	adcl	$0, woken_seq+4(%ebx) + +24:	subl	$(1 << nwaiters_shift), cond_nwaiters(%ebx) + +	/* Wake up a thread which wants to destroy the condvar object.  */ +	movl	total_seq(%ebx), %eax +	andl	total_seq+4(%ebx), %eax +	cmpl	$0xffffffff, %eax +	jne	25f +	movl	cond_nwaiters(%ebx), %eax +	andl	$~((1 << nwaiters_shift) - 1), %eax +	jne	25f + +	addl	$cond_nwaiters, %ebx +	movl	$SYS_futex, %eax +#if FUTEX_PRIVATE_FLAG > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex-cond_nwaiters(%ebx) +	sete	%cl +	subl	$1, %ecx +#ifdef __ASSUME_PRIVATE_FUTEX +	andl	$FUTEX_PRIVATE_FLAG, %ecx +#else +	andl	%gs:PRIVATE_FUTEX, %ecx +#endif +	addl	$FUTEX_WAKE, %ecx +	movl	$1, %edx +	ENTER_KERNEL +	subl	$cond_nwaiters, %ebx + +25:	LOCK +#if cond_lock == 0 +	subl	$1, (%ebx) +#else +	subl	$1, cond_lock(%ebx) +#endif +	jne	10f + +11:	movl	24+FRAME_SIZE(%esp), %eax +	/* With requeue_pi, the mutex lock is held in the kernel.  */ +	movl	24(%esp), %ecx +	testl	%ecx, %ecx +	jnz	27f + +	call	__pthread_mutex_cond_lock +26:	addl	$FRAME_SIZE, %esp +	cfi_adjust_cfa_offset(-FRAME_SIZE); + +	/* We return the result of the mutex_lock operation if it failed.  */ +	testl	%eax, %eax +#ifdef HAVE_CMOV +	cmovel	%esi, %eax +#else +	jne	22f +	movl	%esi, %eax +22: +#endif + +18:	popl	%ebx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebx) +	popl	%esi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%esi) +	popl	%edi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%edi) +	popl	%ebp +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebp) + +	ret + +	cfi_restore_state + +27:	call	__pthread_mutex_cond_lock_adjust +	xorl	%eax, %eax +	jmp	26b + +	cfi_adjust_cfa_offset(-FRAME_SIZE); +	/* Initial locking failed.  */ +1: +#if cond_lock == 0 +	movl	%ebx, %edx +#else +	leal	cond_lock(%ebx), %edx +#endif +#if (LLL_SHARED-LLL_PRIVATE) > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex(%ebx) +	setne	%cl +	subl	$1, %ecx +	andl	$(LLL_SHARED-LLL_PRIVATE), %ecx +#if LLL_PRIVATE != 0 +	addl	$LLL_PRIVATE, %ecx +#endif +	call	__lll_lock_wait +	jmp	2b + +	/* The initial unlocking of the mutex failed.  */ +16: +	LOCK +#if cond_lock == 0 +	subl	$1, (%ebx) +#else +	subl	$1, cond_lock(%ebx) +#endif +	jne	18b + +	movl	%eax, %esi +#if cond_lock == 0 +	movl	%ebx, %eax +#else +	leal	cond_lock(%ebx), %eax +#endif +#if (LLL_SHARED-LLL_PRIVATE) > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex(%ebx) +	setne	%cl +	subl	$1, %ecx +	andl	$(LLL_SHARED-LLL_PRIVATE), %ecx +#if LLL_PRIVATE != 0 +	addl	$LLL_PRIVATE, %ecx +#endif +	call	__lll_unlock_wake + +	movl	%esi, %eax +	jmp	18b + +	cfi_adjust_cfa_offset(FRAME_SIZE) + +	/* Unlock in loop requires wakeup.  */ +3: +#if cond_lock == 0 +	movl	%ebx, %eax +#else +	leal	cond_lock(%ebx), %eax +#endif +#if (LLL_SHARED-LLL_PRIVATE) > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex(%ebx) +	setne	%cl +	subl	$1, %ecx +	andl	$(LLL_SHARED-LLL_PRIVATE), %ecx +#if LLL_PRIVATE != 0 +	addl	$LLL_PRIVATE, %ecx +#endif +	call	__lll_unlock_wake +	jmp	4b + +	/* Locking in loop failed.  */ +5: +#if cond_lock == 0 +	movl	%ebx, %edx +#else +	leal	cond_lock(%ebx), %edx +#endif +#if (LLL_SHARED-LLL_PRIVATE) > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex(%ebx) +	setne	%cl +	subl	$1, %ecx +	andl	$(LLL_SHARED-LLL_PRIVATE), %ecx +#if LLL_PRIVATE != 0 +	addl	$LLL_PRIVATE, %ecx +#endif +	call	__lll_lock_wait +	jmp	6b + +	/* Unlock after loop requires wakeup.  */ +10: +#if cond_lock == 0 +	movl	%ebx, %eax +#else +	leal	cond_lock(%ebx), %eax +#endif +#if (LLL_SHARED-LLL_PRIVATE) > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex(%ebx) +	setne	%cl +	subl	$1, %ecx +	andl	$(LLL_SHARED-LLL_PRIVATE), %ecx +#if LLL_PRIVATE != 0 +	addl	$LLL_PRIVATE, %ecx +#endif +	call	__lll_unlock_wake +	jmp	11b + +#if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS +	/* clock_gettime not available.  */ +19:	leal	4(%esp), %ebx +	xorl	%ecx, %ecx +	movl	$__NR_gettimeofday, %eax +	ENTER_KERNEL +	movl	%edx, %ebx + +	/* Compute relative timeout.  */ +	movl	8(%esp), %eax +	movl	$1000, %edx +	mul	%edx		/* Milli seconds to nano seconds.  */ +	movl	(%ebp), %ecx +	movl	4(%ebp), %edx +	subl	4(%esp), %ecx +	subl	%eax, %edx +	jns	20f +	addl	$1000000000, %edx +	subl	$1, %ecx +20:	testl	%ecx, %ecx +	movl	$-ETIMEDOUT, %esi +	js	6b +	jmp	21b +#endif +	.size	__pthread_cond_timedwait, .-__pthread_cond_timedwait +weak_alias(__pthread_cond_timedwait, pthread_cond_timedwait) + + +	.type	__condvar_tw_cleanup2, @function +__condvar_tw_cleanup2: +	subl	$cond_futex, %ebx +	.size	__condvar_tw_cleanup2, .-__condvar_tw_cleanup2 +	.type	__condvar_tw_cleanup, @function +__condvar_tw_cleanup: +	movl	%eax, %esi + +	/* Get internal lock.  */ +	movl	$1, %edx +	xorl	%eax, %eax +	LOCK +#if cond_lock == 0 +	cmpxchgl %edx, (%ebx) +#else +	cmpxchgl %edx, cond_lock(%ebx) +#endif +	jz	1f + +#if cond_lock == 0 +	movl	%ebx, %edx +#else +	leal	cond_lock(%ebx), %edx +#endif +#if (LLL_SHARED-LLL_PRIVATE) > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex(%ebx) +	setne	%cl +	subl	$1, %ecx +	andl	$(LLL_SHARED-LLL_PRIVATE), %ecx +#if LLL_PRIVATE != 0 +	addl	$LLL_PRIVATE, %ecx +#endif +	call	__lll_lock_wait + +1:	movl	broadcast_seq(%ebx), %eax +	cmpl	20(%esp), %eax +	jne	3f + +	/* We increment the wakeup_seq counter only if it is lower than +	   total_seq.  If this is not the case the thread was woken and +	   then canceled.  In this case we ignore the signal.  */ +	movl	total_seq(%ebx), %eax +	movl	total_seq+4(%ebx), %edi +	cmpl	wakeup_seq+4(%ebx), %edi +	jb	6f +	ja	7f +	cmpl	wakeup_seq(%ebx), %eax +	jbe	7f + +6:	addl	$1, wakeup_seq(%ebx) +	adcl	$0, wakeup_seq+4(%ebx) +	addl	$1, cond_futex(%ebx) + +7:	addl	$1, woken_seq(%ebx) +	adcl	$0, woken_seq+4(%ebx) + +3:	subl	$(1 << nwaiters_shift), cond_nwaiters(%ebx) + +	/* Wake up a thread which wants to destroy the condvar object.  */ +	xorl	%edi, %edi +	movl	total_seq(%ebx), %eax +	andl	total_seq+4(%ebx), %eax +	cmpl	$0xffffffff, %eax +	jne	4f +	movl	cond_nwaiters(%ebx), %eax +	andl	$~((1 << nwaiters_shift) - 1), %eax +	jne	4f + +	addl	$cond_nwaiters, %ebx +	movl	$SYS_futex, %eax +#if FUTEX_PRIVATE_FLAG > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex-cond_nwaiters(%ebx) +	sete	%cl +	subl	$1, %ecx +#ifdef __ASSUME_PRIVATE_FUTEX +	andl	$FUTEX_PRIVATE_FLAG, %ecx +#else +	andl	%gs:PRIVATE_FUTEX, %ecx +#endif +	addl	$FUTEX_WAKE, %ecx +	movl	$1, %edx +	ENTER_KERNEL +	subl	$cond_nwaiters, %ebx +	movl	$1, %edi + +4:	LOCK +#if cond_lock == 0 +	subl	$1, (%ebx) +#else +	subl	$1, cond_lock(%ebx) +#endif +	je	2f + +#if cond_lock == 0 +	movl	%ebx, %eax +#else +	leal	cond_lock(%ebx), %eax +#endif +#if (LLL_SHARED-LLL_PRIVATE) > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex(%ebx) +	setne	%cl +	subl	$1, %ecx +	andl	$(LLL_SHARED-LLL_PRIVATE), %ecx +#if LLL_PRIVATE != 0 +	addl	$LLL_PRIVATE, %ecx +#endif +	call	__lll_unlock_wake + +	/* Wake up all waiters to make sure no signal gets lost.  */ +2:	testl	%edi, %edi +	jnz	5f +	addl	$cond_futex, %ebx +#if FUTEX_PRIVATE_FLAG > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex-cond_futex(%ebx) +	sete	%cl +	subl	$1, %ecx +#ifdef __ASSUME_PRIVATE_FUTEX +	andl	$FUTEX_PRIVATE_FLAG, %ecx +#else +	andl	%gs:PRIVATE_FUTEX, %ecx +#endif +	addl	$FUTEX_WAKE, %ecx +	movl	$SYS_futex, %eax +	movl	$0x7fffffff, %edx +	ENTER_KERNEL + +5:	movl	24+FRAME_SIZE(%esp), %eax +	call	__pthread_mutex_cond_lock + +	movl	%esi, (%esp) +.LcallUR: +	call	_Unwind_Resume +	hlt +.LENDCODE: +	cfi_endproc +	.size	__condvar_tw_cleanup, .-__condvar_tw_cleanup + + +	.section .gcc_except_table,"a",@progbits +.LexceptSTART: +	.byte	DW_EH_PE_omit			# @LPStart format (omit) +	.byte	DW_EH_PE_omit			# @TType format (omit) +	.byte	DW_EH_PE_sdata4			# call-site format +						# DW_EH_PE_sdata4 +	.uleb128 .Lcstend-.Lcstbegin +.Lcstbegin: +	.long	.LcleanupSTART-.LSTARTCODE +	.long	.Ladd_cond_futex-.LcleanupSTART +	.long	__condvar_tw_cleanup-.LSTARTCODE +	.uleb128  0 +	.long	.Ladd_cond_futex-.LSTARTCODE +	.long	.Lsub_cond_futex-.Ladd_cond_futex +	.long	__condvar_tw_cleanup2-.LSTARTCODE +	.uleb128  0 +	.long	.Lsub_cond_futex-.LSTARTCODE +	.long	.LcleanupEND-.Lsub_cond_futex +	.long	__condvar_tw_cleanup-.LSTARTCODE +	.uleb128  0 +	.long	.LcallUR-.LSTARTCODE +	.long	.LENDCODE-.LcallUR +	.long	0 +	.uleb128  0 +.Lcstend: + + +#ifdef SHARED +	.hidden DW.ref.__gcc_personality_v0 +	.weak	DW.ref.__gcc_personality_v0 +	.section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits +	.align	4 +	.type	DW.ref.__gcc_personality_v0, @object +	.size	DW.ref.__gcc_personality_v0, 4 +DW.ref.__gcc_personality_v0: +	.long   __gcc_personality_v0 +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S new file mode 100644 index 000000000..006fc510c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S @@ -0,0 +1,591 @@ +/* Copyright (C) 2002-2004,2006-2007,2009,2010 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelcond.h> +#include <tcb-offsets.h> +#include <pthread-errnos.h> +#include <pthread-pi-defines.h> +#include <bits/kernel-features.h> + + +	.text + +/* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)  */ +	.globl	__pthread_cond_wait +	.type	__pthread_cond_wait, @function +	.protected	__pthread_cond_wait +	.align	16 +__pthread_cond_wait: +.LSTARTCODE: +	cfi_startproc +#ifdef SHARED +	cfi_personality(DW_EH_PE_pcrel | DW_EH_PE_sdata4 | DW_EH_PE_indirect, +			DW.ref.__gcc_personality_v0) +	cfi_lsda(DW_EH_PE_pcrel | DW_EH_PE_sdata4, .LexceptSTART) +#else +	cfi_personality(DW_EH_PE_udata4, __gcc_personality_v0) +	cfi_lsda(DW_EH_PE_udata4, .LexceptSTART) +#endif + +	pushl	%ebp +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset(%ebp, 0) +	pushl	%edi +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset(%edi, 0) +	pushl	%esi +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset(%esi, 0) +	pushl	%ebx +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset(%ebx, 0) + +	xorl	%esi, %esi +	movl	20(%esp), %ebx + +	/* Get internal lock.  */ +	movl	$1, %edx +	xorl	%eax, %eax +	LOCK +#if cond_lock == 0 +	cmpxchgl %edx, (%ebx) +#else +	cmpxchgl %edx, cond_lock(%ebx) +#endif +	jnz	1f + +	/* Store the reference to the mutex.  If there is already a +	   different value in there this is a bad user bug.  */ +2:	cmpl	$-1, dep_mutex(%ebx) +	movl	24(%esp), %eax +	je	15f +	movl	%eax, dep_mutex(%ebx) + +	/* Unlock the mutex.  */ +15:	xorl	%edx, %edx +	call	__pthread_mutex_unlock_usercnt + +	testl	%eax, %eax +	jne	12f + +	addl	$1, total_seq(%ebx) +	adcl	$0, total_seq+4(%ebx) +	addl	$1, cond_futex(%ebx) +	addl	$(1 << nwaiters_shift), cond_nwaiters(%ebx) + +#define FRAME_SIZE 20 +	subl	$FRAME_SIZE, %esp +	cfi_adjust_cfa_offset(FRAME_SIZE) +	cfi_remember_state + +	/* Get and store current wakeup_seq value.  */ +	movl	wakeup_seq(%ebx), %edi +	movl	wakeup_seq+4(%ebx), %edx +	movl	broadcast_seq(%ebx), %eax +	movl	%edi, 4(%esp) +	movl	%edx, 8(%esp) +	movl	%eax, 12(%esp) + +	/* Reset the pi-requeued flag.  */ +8:	movl	$0, 16(%esp) +	movl	cond_futex(%ebx), %ebp + +	/* Unlock.  */ +	LOCK +#if cond_lock == 0 +	subl	$1, (%ebx) +#else +	subl	$1, cond_lock(%ebx) +#endif +	jne	3f + +.LcleanupSTART: +4:	call	__pthread_enable_asynccancel +	movl	%eax, (%esp) + +	xorl	%ecx, %ecx +	cmpl	$-1, dep_mutex(%ebx) +	sete	%cl +	je	18f + +	movl	dep_mutex(%ebx), %edi +	/* Requeue to a non-robust PI mutex if the PI bit is set and +	   the robust bit is not set.  */ +	movl	MUTEX_KIND(%edi), %eax +	andl	$(ROBUST_BIT|PI_BIT), %eax +	cmpl	$PI_BIT, %eax +	jne	18f + +	movl	$(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %ecx +	movl	%ebp, %edx +	xorl	%esi, %esi +	addl	$cond_futex, %ebx +	movl	$SYS_futex, %eax +	ENTER_KERNEL +	subl	$cond_futex, %ebx +	/* Set the pi-requeued flag only if the kernel has returned 0. The +	   kernel does not hold the mutex on error.  */ +	cmpl	$0, %eax +	sete	16(%esp) +	je	19f + +	/* Normal and PI futexes dont mix. Use normal futex functions only +	   if the kernel does not support the PI futex functions.  */ +	cmpl	$-ENOSYS, %eax +	jne	19f +	xorl	%ecx, %ecx + +18:	subl	$1, %ecx +#ifdef __ASSUME_PRIVATE_FUTEX +	andl	$FUTEX_PRIVATE_FLAG, %ecx +#else +	andl	%gs:PRIVATE_FUTEX, %ecx +#endif +#if FUTEX_WAIT != 0 +	addl	$FUTEX_WAIT, %ecx +#endif +	movl	%ebp, %edx +	addl	$cond_futex, %ebx +.Ladd_cond_futex: +	movl	$SYS_futex, %eax +	ENTER_KERNEL +	subl	$cond_futex, %ebx +.Lsub_cond_futex: + +19:	movl	(%esp), %eax +	call	__pthread_disable_asynccancel +.LcleanupEND: + +	/* Lock.  */ +	movl	$1, %edx +	xorl	%eax, %eax +	LOCK +#if cond_lock == 0 +	cmpxchgl %edx, (%ebx) +#else +	cmpxchgl %edx, cond_lock(%ebx) +#endif +	jnz	5f + +6:	movl	broadcast_seq(%ebx), %eax +	cmpl	12(%esp), %eax +	jne	16f + +	movl	woken_seq(%ebx), %eax +	movl	woken_seq+4(%ebx), %ecx + +	movl	wakeup_seq(%ebx), %edi +	movl	wakeup_seq+4(%ebx), %edx + +	cmpl	8(%esp), %edx +	jne	7f +	cmpl	4(%esp), %edi +	je	8b + +7:	cmpl	%ecx, %edx +	jne	9f +	cmp	%eax, %edi +	je	8b + +9:	addl	$1, woken_seq(%ebx) +	adcl	$0, woken_seq+4(%ebx) + +	/* Unlock */ +16:	subl	$(1 << nwaiters_shift), cond_nwaiters(%ebx) + +	/* Wake up a thread which wants to destroy the condvar object.  */ +	movl	total_seq(%ebx), %eax +	andl	total_seq+4(%ebx), %eax +	cmpl	$0xffffffff, %eax +	jne	17f +	movl	cond_nwaiters(%ebx), %eax +	andl	$~((1 << nwaiters_shift) - 1), %eax +	jne	17f + +	addl	$cond_nwaiters, %ebx +	movl	$SYS_futex, %eax +#if FUTEX_PRIVATE_FLAG > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex-cond_nwaiters(%ebx) +	sete	%cl +	subl	$1, %ecx +#ifdef __ASSUME_PRIVATE_FUTEX +	andl	$FUTEX_PRIVATE_FLAG, %ecx +#else +	andl	%gs:PRIVATE_FUTEX, %ecx +#endif +	addl	$FUTEX_WAKE, %ecx +	movl	$1, %edx +	ENTER_KERNEL +	subl	$cond_nwaiters, %ebx + +17:	LOCK +#if cond_lock == 0 +	subl	$1, (%ebx) +#else +	subl	$1, cond_lock(%ebx) +#endif +	jne	10f + +	/* With requeue_pi, the mutex lock is held in the kernel.  */ +11:	movl	24+FRAME_SIZE(%esp), %eax +	movl	16(%esp), %ecx +	testl	%ecx, %ecx +	jnz	21f + +	call	__pthread_mutex_cond_lock +20:	addl	$FRAME_SIZE, %esp +	cfi_adjust_cfa_offset(-FRAME_SIZE); + +14:	popl	%ebx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebx) +	popl	%esi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%esi) +	popl	%edi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%edi) +	popl	%ebp +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebp) + +	/* We return the result of the mutex_lock operation.  */ +	ret + +	cfi_restore_state + +21:	call	__pthread_mutex_cond_lock_adjust +	xorl	%eax, %eax +	jmp	20b + +	cfi_adjust_cfa_offset(-FRAME_SIZE); +	/* Initial locking failed.  */ +1: +#if cond_lock == 0 +	movl	%ebx, %edx +#else +	leal	cond_lock(%ebx), %edx +#endif +#if (LLL_SHARED-LLL_PRIVATE) > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex(%ebx) +	setne	%cl +	subl	$1, %ecx +	andl	$(LLL_SHARED-LLL_PRIVATE), %ecx +#if LLL_PRIVATE != 0 +	addl	$LLL_PRIVATE, %ecx +#endif +	call	__lll_lock_wait +	jmp	2b + +	/* The initial unlocking of the mutex failed.  */ +12: +	LOCK +#if cond_lock == 0 +	subl	$1, (%ebx) +#else +	subl	$1, cond_lock(%ebx) +#endif +	jne	14b + +	movl	%eax, %esi +#if cond_lock == 0 +	movl	%ebx, %eax +#else +	leal	cond_lock(%ebx), %eax +#endif +#if (LLL_SHARED-LLL_PRIVATE) > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex(%ebx) +	setne	%cl +	subl	$1, %ecx +	andl	$(LLL_SHARED-LLL_PRIVATE), %ecx +#if LLL_PRIVATE != 0 +	addl	$LLL_PRIVATE, %ecx +#endif +	call	__lll_unlock_wake + +	movl	%esi, %eax +	jmp	14b + +	cfi_adjust_cfa_offset(FRAME_SIZE) + +	/* Unlock in loop requires wakeup.  */ +3: +#if cond_lock == 0 +	movl	%ebx, %eax +#else +	leal	cond_lock(%ebx), %eax +#endif +#if (LLL_SHARED-LLL_PRIVATE) > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex(%ebx) +	setne	%cl +	subl	$1, %ecx +	andl	$(LLL_SHARED-LLL_PRIVATE), %ecx +#if LLL_PRIVATE != 0 +	addl	$LLL_PRIVATE, %ecx +#endif +	call	__lll_unlock_wake +	jmp	4b + +	/* Locking in loop failed.  */ +5: +#if cond_lock == 0 +	movl	%ebx, %edx +#else +	leal	cond_lock(%ebx), %edx +#endif +#if (LLL_SHARED-LLL_PRIVATE) > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex(%ebx) +	setne	%cl +	subl	$1, %ecx +	andl	$(LLL_SHARED-LLL_PRIVATE), %ecx +#if LLL_PRIVATE != 0 +	addl	$LLL_PRIVATE, %ecx +#endif +	call	__lll_lock_wait +	jmp	6b + +	/* Unlock after loop requires wakeup.  */ +10: +#if cond_lock == 0 +	movl	%ebx, %eax +#else +	leal	cond_lock(%ebx), %eax +#endif +#if (LLL_SHARED-LLL_PRIVATE) > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex(%ebx) +	setne	%cl +	subl	$1, %ecx +	andl	$(LLL_SHARED-LLL_PRIVATE), %ecx +#if LLL_PRIVATE != 0 +	addl	$LLL_PRIVATE, %ecx +#endif +	call	__lll_unlock_wake +	jmp	11b +	.size	__pthread_cond_wait, .-__pthread_cond_wait +weak_alias(__pthread_cond_wait, pthread_cond_wait) + + +	.type	__condvar_w_cleanup2, @function +__condvar_w_cleanup2: +	subl	$cond_futex, %ebx +	.size	__condvar_w_cleanup2, .-__condvar_w_cleanup2 +.LSbl4: +	.type	__condvar_w_cleanup, @function +__condvar_w_cleanup: +	movl	%eax, %esi + +	/* Get internal lock.  */ +	movl	$1, %edx +	xorl	%eax, %eax +	LOCK +#if cond_lock == 0 +	cmpxchgl %edx, (%ebx) +#else +	cmpxchgl %edx, cond_lock(%ebx) +#endif +	jz	1f + +#if cond_lock == 0 +	movl	%ebx, %edx +#else +	leal	cond_lock(%ebx), %edx +#endif +#if (LLL_SHARED-LLL_PRIVATE) > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex(%ebx) +	setne	%cl +	subl	$1, %ecx +	andl	$(LLL_SHARED-LLL_PRIVATE), %ecx +#if LLL_PRIVATE != 0 +	addl	$LLL_PRIVATE, %ecx +#endif +	call	__lll_lock_wait + +1:	movl	broadcast_seq(%ebx), %eax +	cmpl	12(%esp), %eax +	jne	3f + +	/* We increment the wakeup_seq counter only if it is lower than +	   total_seq.  If this is not the case the thread was woken and +	   then canceled.  In this case we ignore the signal.  */ +	movl	total_seq(%ebx), %eax +	movl	total_seq+4(%ebx), %edi +	cmpl	wakeup_seq+4(%ebx), %edi +	jb	6f +	ja	7f +	cmpl	wakeup_seq(%ebx), %eax +	jbe	7f + +6:	addl	$1, wakeup_seq(%ebx) +	adcl	$0, wakeup_seq+4(%ebx) +	addl	$1, cond_futex(%ebx) + +7:	addl	$1, woken_seq(%ebx) +	adcl	$0, woken_seq+4(%ebx) + +3:	subl	$(1 << nwaiters_shift), cond_nwaiters(%ebx) + +	/* Wake up a thread which wants to destroy the condvar object.  */ +	xorl	%edi, %edi +	movl	total_seq(%ebx), %eax +	andl	total_seq+4(%ebx), %eax +	cmpl	$0xffffffff, %eax +	jne	4f +	movl	cond_nwaiters(%ebx), %eax +	andl	$~((1 << nwaiters_shift) - 1), %eax +	jne	4f + +	addl	$cond_nwaiters, %ebx +	movl	$SYS_futex, %eax +#if FUTEX_PRIVATE_FLAG > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex-cond_nwaiters(%ebx) +	sete	%cl +	subl	$1, %ecx +#ifdef __ASSUME_PRIVATE_FUTEX +	andl	$FUTEX_PRIVATE_FLAG, %ecx +#else +	andl	%gs:PRIVATE_FUTEX, %ecx +#endif +	addl	$FUTEX_WAKE, %ecx +	movl	$1, %edx +	ENTER_KERNEL +	subl	$cond_nwaiters, %ebx +	movl	$1, %edi + +4:	LOCK +#if cond_lock == 0 +	subl	$1, (%ebx) +#else +	subl	$1, cond_lock(%ebx) +#endif +	je	2f + +#if cond_lock == 0 +	movl	%ebx, %eax +#else +	leal	cond_lock(%ebx), %eax +#endif +#if (LLL_SHARED-LLL_PRIVATE) > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex(%ebx) +	setne	%cl +	subl	$1, %ecx +	andl	$(LLL_SHARED-LLL_PRIVATE), %ecx +#if LLL_PRIVATE != 0 +	addl	$LLL_PRIVATE, %ecx +#endif +	call	__lll_unlock_wake + +	/* Wake up all waiters to make sure no signal gets lost.  */ +2:	testl	%edi, %edi +	jnz	5f +	addl	$cond_futex, %ebx +#if FUTEX_PRIVATE_FLAG > 255 +	xorl	%ecx, %ecx +#endif +	cmpl	$-1, dep_mutex-cond_futex(%ebx) +	sete	%cl +	subl	$1, %ecx +#ifdef __ASSUME_PRIVATE_FUTEX +	andl	$FUTEX_PRIVATE_FLAG, %ecx +#else +	andl	%gs:PRIVATE_FUTEX, %ecx +#endif +	addl	$FUTEX_WAKE, %ecx +	movl	$SYS_futex, %eax +	movl	$0x7fffffff, %edx +	ENTER_KERNEL + +5:	movl	24+FRAME_SIZE(%esp), %eax +	call	__pthread_mutex_cond_lock + +	movl	%esi, (%esp) +.LcallUR: +	call	_Unwind_Resume +	hlt +.LENDCODE: +	cfi_endproc +	.size	__condvar_w_cleanup, .-__condvar_w_cleanup + + +	.section .gcc_except_table,"a",@progbits +.LexceptSTART: +	.byte	DW_EH_PE_omit			# @LPStart format (omit) +	.byte	DW_EH_PE_omit			# @TType format (omit) +	.byte	DW_EH_PE_sdata4			# call-site format +						# DW_EH_PE_sdata4 +	.uleb128 .Lcstend-.Lcstbegin +.Lcstbegin: +	.long	.LcleanupSTART-.LSTARTCODE +	.long	.Ladd_cond_futex-.LcleanupSTART +	.long	__condvar_w_cleanup-.LSTARTCODE +	.uleb128  0 +	.long	.Ladd_cond_futex-.LSTARTCODE +	.long	.Lsub_cond_futex-.Ladd_cond_futex +	.long	__condvar_w_cleanup2-.LSTARTCODE +	.uleb128  0 +	.long	.Lsub_cond_futex-.LSTARTCODE +	.long	.LcleanupEND-.Lsub_cond_futex +	.long	__condvar_w_cleanup-.LSTARTCODE +	.uleb128  0 +	.long	.LcallUR-.LSTARTCODE +	.long	.LENDCODE-.LcallUR +	.long	0 +	.uleb128  0 +.Lcstend: + +#ifdef __PIC__ +	.section .gnu.linkonce.t.__i686.get_pc_thunk.cx,"ax",@progbits +	.globl	__i686.get_pc_thunk.cx +	.hidden	__i686.get_pc_thunk.cx +	.type	__i686.get_pc_thunk.cx,@function +__i686.get_pc_thunk.cx: +	movl (%esp), %ecx; +	ret +	.size	__i686.get_pc_thunk.cx,.-__i686.get_pc_thunk.cx +#endif + +#ifdef SHARED +	.hidden DW.ref.__gcc_personality_v0 +	.weak   DW.ref.__gcc_personality_v0 +	.section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits +	.align 4 +	.type   DW.ref.__gcc_personality_v0, @object +	.size   DW.ref.__gcc_personality_v0, 4 +DW.ref.__gcc_personality_v0: +	.long   __gcc_personality_v0 +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S new file mode 100644 index 000000000..79501bd56 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S @@ -0,0 +1,195 @@ +/* Copyright (C) 2002, 2003, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <bits/kernel-features.h> +#include <tls.h> + + +	.text + +	.globl	__pthread_rwlock_rdlock +	.type	__pthread_rwlock_rdlock,@function +	.protected	__pthread_rwlock_rdlock +	.align	16 +__pthread_rwlock_rdlock: +	cfi_startproc +	pushl	%esi +	cfi_adjust_cfa_offset(4) +	pushl	%ebx +	cfi_adjust_cfa_offset(4) +	cfi_offset(%esi, -8) +	cfi_offset(%ebx, -12) + +	xorl	%esi, %esi +	movl	12(%esp), %ebx + +	/* Get the lock.  */ +	movl	$1, %edx +	xorl	%eax, %eax +	LOCK +#if MUTEX == 0 +	cmpxchgl %edx, (%ebx) +#else +	cmpxchgl %edx, MUTEX(%ebx) +#endif +	jnz	1f + +2:	movl	WRITER(%ebx), %eax +	testl	%eax, %eax +	jne	14f +	cmpl	$0, WRITERS_QUEUED(%ebx) +	je	5f +	cmpb	$0, FLAGS(%ebx) +	je	5f + +3:	addl	$1, READERS_QUEUED(%ebx) +	je	4f + +	movl	READERS_WAKEUP(%ebx), %edx + +	LOCK +#if MUTEX == 0 +	subl	$1, (%ebx) +#else +	subl	$1, MUTEX(%ebx) +#endif +	jne	10f + +11: +#ifdef __ASSUME_PRIVATE_FUTEX +	movzbl	PSHARED(%ebx), %ecx +	xorl	$FUTEX_PRIVATE_FLAG|FUTEX_WAIT, %ecx +#else +	movzbl	PSHARED(%ebx), %ecx +# if FUTEX_WAIT != 0 +	orl	$FUTEX_WAIT, %ecx +# endif +	xorl	%gs:PRIVATE_FUTEX, %ecx +#endif +	addl	$READERS_WAKEUP, %ebx +	movl	$SYS_futex, %eax +	ENTER_KERNEL + +	subl	$READERS_WAKEUP, %ebx + +	/* Reget the lock.  */ +	movl	$1, %edx +	xorl	%eax, %eax +	LOCK +#if MUTEX == 0 +	cmpxchgl %edx, (%ebx) +#else +	cmpxchgl %edx, MUTEX(%ebx) +#endif +	jnz	12f + +13:	subl	$1, READERS_QUEUED(%ebx) +	jmp	2b + +5:	xorl	%edx, %edx +	addl	$1, NR_READERS(%ebx) +	je	8f +9:	LOCK +#if MUTEX == 0 +	subl	$1, (%ebx) +#else +	subl	$1, MUTEX(%ebx) +#endif +	jne	6f +7: + +	movl	%edx, %eax +	popl	%ebx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebx) +	popl	%esi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%esi) +	ret + +	cfi_adjust_cfa_offset(8) +	cfi_offset(%esi, -8) +	cfi_offset(%ebx, -12) +1: +#if MUTEX == 0 +	movl	%ebx, %edx +#else +	leal	MUTEX(%ebx), %edx +#endif +	movzbl	PSHARED(%ebx), %ecx +	call	__lll_lock_wait +	jmp	2b + +14:	cmpl	%gs:TID, %eax +	jne	3b +	/* Deadlock detected.  */ +	movl	$EDEADLK, %edx +	jmp	9b + +6: +#if MUTEX == 0 +	movl	%ebx, %eax +#else +	leal	MUTEX(%ebx), %eax +#endif +	movzbl	PSHARED(%ebx), %ecx +	call	__lll_unlock_wake +	jmp	7b + +	/* Overflow.  */ +8:	subl	$1, NR_READERS(%ebx) +	movl	$EAGAIN, %edx +	jmp	9b + +	/* Overflow.  */ +4:	subl	$1, READERS_QUEUED(%ebx) +	movl	$EAGAIN, %edx +	jmp	9b + +10: +#if MUTEX == 0 +	movl	%ebx, %eax +#else +	leal	MUTEX(%ebx), %eax +#endif +	movzbl	PSHARED(%ebx), %ecx +	call	__lll_unlock_wake +	jmp	11b + +12: +#if MUTEX == 0 +	movl	%ebx, %edx +#else +	leal	MUTEX(%ebx), %edx +#endif +	movzbl	PSHARED(%ebx), %ecx +	call	__lll_lock_wait +	jmp	13b +	cfi_endproc +	.size	__pthread_rwlock_rdlock,.-__pthread_rwlock_rdlock + +	.globl	pthread_rwlock_rdlock +pthread_rwlock_rdlock = __pthread_rwlock_rdlock + +	.globl	__pthread_rwlock_rdlock_internal +__pthread_rwlock_rdlock_internal = __pthread_rwlock_rdlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S new file mode 100644 index 000000000..be4530e13 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S @@ -0,0 +1,245 @@ +/* Copyright (C) 2002, 2003, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <bits/kernel-features.h> +#include <tls.h> + + +	.text + +	.globl	pthread_rwlock_timedrdlock +	.type	pthread_rwlock_timedrdlock,@function +	.align	16 +pthread_rwlock_timedrdlock: +	cfi_startproc +	pushl	%esi +	cfi_adjust_cfa_offset(4) +	pushl	%edi +	cfi_adjust_cfa_offset(4) +	pushl	%ebx +	cfi_adjust_cfa_offset(4) +	pushl	%ebp +	cfi_adjust_cfa_offset(4) +	cfi_offset(%esi, -8) +	cfi_offset(%edi, -12) +	cfi_offset(%ebx, -16) +	cfi_offset(%ebp, -20) +	subl	$8, %esp +	cfi_adjust_cfa_offset(8) + +	movl	28(%esp), %ebp +	movl	32(%esp), %edi + +	/* Get the lock.  */ +	movl	$1, %edx +	xorl	%eax, %eax +	LOCK +#if MUTEX == 0 +	cmpxchgl %edx, (%ebp) +#else +	cmpxchgl %edx, MUTEX(%ebp) +#endif +	jnz	1f + +2:	movl	WRITER(%ebp), %eax +	testl	%eax, %eax +	jne	14f +	cmpl	$0, WRITERS_QUEUED(%ebp) +	je	5f +	cmpb	$0, FLAGS(%ebp) +	je	5f + +	/* Check the value of the timeout parameter.  */ +3:	cmpl	$1000000000, 4(%edi) +	jae	19f + +	addl	$1, READERS_QUEUED(%ebp) +	je	4f + +	movl	READERS_WAKEUP(%ebp), %esi + +	LOCK +#if MUTEX == 0 +	subl	$1, (%ebp) +#else +	subl	$1, MUTEX(%ebp) +#endif +	jne	10f + +	/* Get current time.  */ +11:	movl	%esp, %ebx +	xorl	%ecx, %ecx +	movl	$__NR_gettimeofday, %eax +	ENTER_KERNEL + +	/* Compute relative timeout.  */ +	movl	4(%esp), %eax +	movl	$1000, %edx +	mul	%edx		/* Milli seconds to nano seconds.  */ +	movl	(%edi), %ecx +	movl	4(%edi), %edx +	subl	(%esp), %ecx +	subl	%eax, %edx +	jns	15f +	addl	$1000000000, %edx +	subl	$1, %ecx +15:	testl	%ecx, %ecx +	js	16f		/* Time is already up.  */ + +	/* Futex call.  */ +	movl	%ecx, (%esp)	/* Store relative timeout.  */ +	movl	%edx, 4(%esp) + +	movl	%esi, %edx +#ifdef __ASSUME_PRIVATE_FUTEX +	movzbl	PSHARED(%ebp), %ecx +	xorl	$FUTEX_PRIVATE_FLAG|FUTEX_WAIT, %ecx +#else +	movzbl	PSHARED(%ebp), %ecx +# if FUTEX_WAIT != 0 +	orl	$FUTEX_WAIT, %ecx +# endif +	xorl	%gs:PRIVATE_FUTEX, %ecx +#endif +	movl	%esp, %esi +	leal	READERS_WAKEUP(%ebp), %ebx +	movl	$SYS_futex, %eax +	ENTER_KERNEL +	movl	%eax, %esi +17: + +	/* Reget the lock.  */ +	movl	$1, %edx +	xorl	%eax, %eax +	LOCK +#if MUTEX == 0 +	cmpxchgl %edx, (%ebp) +#else +	cmpxchgl %edx, MUTEX(%ebp) +#endif +	jnz	12f + +13:	subl	$1, READERS_QUEUED(%ebp) +	cmpl	$-ETIMEDOUT, %esi +	jne	2b + +18:	movl	$ETIMEDOUT, %edx +	jmp	9f + + +5:	xorl	%edx, %edx +	addl	$1, NR_READERS(%ebp) +	je	8f +9:	LOCK +#if MUTEX == 0 +	subl	$1, (%ebp) +#else +	subl	$1, MUTEX(%ebp) +#endif +	jne	6f + +7:	movl	%edx, %eax + +	addl	$8, %esp +	cfi_adjust_cfa_offset(-8) +	popl	%ebp +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebp) +	popl	%ebx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebx) +	popl	%edi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%edi) +	popl	%esi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%esi) +	ret + +	cfi_adjust_cfa_offset(24) +	cfi_offset(%esi, -8) +	cfi_offset(%edi, -12) +	cfi_offset(%ebx, -16) +	cfi_offset(%ebp, -20) +1: +#if MUTEX == 0 +	movl	%ebp, %edx +#else +	leal	MUTEX(%ebp), %edx +#endif +	movzbl	PSHARED(%ebp), %ecx +	call	__lll_lock_wait +	jmp	2b + +14:	cmpl	%gs:TID, %eax +	jne	3b +	movl	$EDEADLK, %edx +	jmp	9b + +6: +#if MUTEX == 0 +	movl	%ebp, %eax +#else +	leal	MUTEX(%ebp), %eax +#endif +	movzbl	PSHARED(%ebp), %ecx +	call	__lll_unlock_wake +	jmp	7b + +	/* Overflow.  */ +8:	subl	$1, NR_READERS(%ebp) +	movl	$EAGAIN, %edx +	jmp	9b + +	/* Overflow.  */ +4:	subl	$1, READERS_QUEUED(%ebp) +	movl	$EAGAIN, %edx +	jmp	9b + +10: +#if MUTEX == 0 +	movl	%ebp, %eax +#else +	leal	MUTEX(%ebp), %eax +#endif +	movzbl	PSHARED(%ebp), %ecx +	call	__lll_unlock_wake +	jmp	11b + +12: +#if MUTEX == 0 +	movl	%ebp, %edx +#else +	leal	MUTEX(%ebp), %edx +#endif +	movzbl	PSHARED(%ebp), %ecx +	call	__lll_lock_wait +	jmp	13b + +16:	movl	$-ETIMEDOUT, %esi +	jmp	17b + +19:	movl	$EINVAL, %edx +	jmp	9b +	cfi_endproc +	.size	pthread_rwlock_timedrdlock,.-pthread_rwlock_timedrdlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S new file mode 100644 index 000000000..61431ab71 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S @@ -0,0 +1,238 @@ +/* Copyright (C) 2002, 2003, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <bits/kernel-features.h> +#include <tls.h> + + +	.text + +	.globl	pthread_rwlock_timedwrlock +	.type	pthread_rwlock_timedwrlock,@function +	.align	16 +pthread_rwlock_timedwrlock: +	cfi_startproc +	pushl	%esi +	cfi_adjust_cfa_offset(4) +	pushl	%edi +	cfi_adjust_cfa_offset(4) +	pushl	%ebx +	cfi_adjust_cfa_offset(4) +	pushl	%ebp +	cfi_adjust_cfa_offset(4) +	cfi_offset(%esi, -8) +	cfi_offset(%edi, -12) +	cfi_offset(%ebx, -16) +	cfi_offset(%ebp, -20) +	subl	$8, %esp +	cfi_adjust_cfa_offset(8) + +	movl	28(%esp), %ebp +	movl	32(%esp), %edi + +	/* Get the lock.  */ +	movl	$1, %edx +	xorl	%eax, %eax +	LOCK +#if MUTEX == 0 +	cmpxchgl %edx, (%ebp) +#else +	cmpxchgl %edx, MUTEX(%ebp) +#endif +	jnz	1f + +2:	movl	WRITER(%ebp), %eax +	testl	%eax, %eax +	jne	14f +	cmpl	$0, NR_READERS(%ebp) +	je	5f + +	/* Check the value of the timeout parameter.  */ +3:	cmpl	$1000000000, 4(%edi) +	jae	19f + +	addl	$1, WRITERS_QUEUED(%ebp) +	je	4f + +	movl	WRITERS_WAKEUP(%ebp), %esi + +	LOCK +#if MUTEX == 0 +	subl	$1, (%ebp) +#else +	subl	$1, MUTEX(%ebp) +#endif +	jne	10f + +	/* Get current time.  */ +11:	movl	%esp, %ebx +	xorl	%ecx, %ecx +	movl	$__NR_gettimeofday, %eax +	ENTER_KERNEL + +	/* Compute relative timeout.  */ +	movl	4(%esp), %eax +	movl	$1000, %edx +	mul	%edx		/* Milli seconds to nano seconds.  */ +	movl	(%edi), %ecx +	movl	4(%edi), %edx +	subl	(%esp), %ecx +	subl	%eax, %edx +	jns	15f +	addl	$1000000000, %edx +	subl	$1, %ecx +15:	testl	%ecx, %ecx +	js	16f		/* Time is already up.  */ + +	/* Futex call.  */ +	movl	%ecx, (%esp)	/* Store relative timeout.  */ +	movl	%edx, 4(%esp) + +	movl	%esi, %edx +#ifdef __ASSUME_PRIVATE_FUTEX +	movzbl	PSHARED(%ebp), %ecx +	xorl	$FUTEX_PRIVATE_FLAG|FUTEX_WAIT, %ecx +#else +	movzbl	PSHARED(%ebp), %ecx +# if FUTEX_WAIT != 0 +	orl	$FUTEX_WAIT, %ecx +# endif +	xorl	%gs:PRIVATE_FUTEX, %ecx +#endif +	movl	%esp, %esi +	leal	WRITERS_WAKEUP(%ebp), %ebx +	movl	$SYS_futex, %eax +	ENTER_KERNEL +	movl	%eax, %esi +17: + +	/* Reget the lock.  */ +	movl	$1, %edx +	xorl	%eax, %eax +	LOCK +#if MUTEX == 0 +	cmpxchgl %edx, (%ebp) +#else +	cmpxchgl %edx, MUTEX(%ebp) +#endif +	jnz	12f + +13:	subl	$1, WRITERS_QUEUED(%ebp) +	cmpl	$-ETIMEDOUT, %esi +	jne	2b + +18:	movl	$ETIMEDOUT, %edx +	jmp	9f + + +5:	xorl	%edx, %edx +	movl	%gs:TID, %eax +	movl	%eax, WRITER(%ebp) +9:	LOCK +#if MUTEX == 0 +	subl	$1, (%ebp) +#else +	subl	$1, MUTEX(%ebp) +#endif +	jne	6f + +7:	movl	%edx, %eax + +	addl	$8, %esp +	cfi_adjust_cfa_offset(-8) +	popl	%ebp +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebp) +	popl	%ebx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebx) +	popl	%edi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%edi) +	popl	%esi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%esi) +	ret + +	cfi_adjust_cfa_offset(24) +	cfi_offset(%esi, -8) +	cfi_offset(%edi, -12) +	cfi_offset(%ebx, -16) +	cfi_offset(%ebp, -20) +1: +#if MUTEX == 0 +	movl	%ebp, %edx +#else +	leal	MUTEX(%ebp), %edx +#endif +	movzbl	PSHARED(%ebp), %ecx +	call	__lll_lock_wait +	jmp	2b + +14:	cmpl	%gs:TID, %eax +	jne	3b +20:	movl	$EDEADLK, %edx +	jmp	9b + +6: +#if MUTEX == 0 +	movl	%ebp, %eax +#else +	leal	MUTEX(%ebp), %eax +#endif +	movzbl	PSHARED(%ebp), %ecx +	call	__lll_unlock_wake +	jmp	7b + +	/* Overflow.  */ +4:	subl	$1, WRITERS_QUEUED(%ebp) +	movl	$EAGAIN, %edx +	jmp	9b + +10: +#if MUTEX == 0 +	movl	%ebp, %eax +#else +	leal	MUTEX(%ebp), %eax +#endif +	movzbl	PSHARED(%ebp), %ecx +	call	__lll_unlock_wake +	jmp	11b + +12: +#if MUTEX == 0 +	movl	%ebp, %edx +#else +	leal	MUTEX(%ebp), %edx +#endif +	movzbl	PSHARED(%ebp), %ecx +	call	__lll_lock_wait +	jmp	13b + +16:	movl	$-ETIMEDOUT, %esi +	jmp	17b + +19:	movl	$EINVAL, %edx +	jmp	9b +	cfi_endproc +	.size	pthread_rwlock_timedwrlock,.-pthread_rwlock_timedwrlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S new file mode 100644 index 000000000..cfab60c67 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S @@ -0,0 +1,157 @@ +/* Copyright (C) 2002, 2003, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelrwlock.h> +#include <bits/kernel-features.h> +#include <tls.h> + + +	.text + +	.globl	__pthread_rwlock_unlock +	.type	__pthread_rwlock_unlock,@function +	.protected	__pthread_rwlock_unlock +	.align	16 +__pthread_rwlock_unlock: +	cfi_startproc +	pushl	%ebx +	cfi_adjust_cfa_offset(4) +	pushl	%edi +	cfi_adjust_cfa_offset(4) +	cfi_offset(%ebx, -8) +	cfi_offset(%edi, -12) + +	movl	12(%esp), %edi + +	/* Get the lock.  */ +	movl	$1, %edx +	xorl	%eax, %eax +	LOCK +#if MUTEX == 0 +	cmpxchgl %edx, (%edi) +#else +	cmpxchgl %edx, MUTEX(%edi) +#endif +	jnz	1f + +2:	cmpl	$0, WRITER(%edi) +	jne	5f +	subl	$1, NR_READERS(%edi) +	jnz	6f + +5:	movl	$0, WRITER(%edi) + +	movl	$1, %edx +	leal	WRITERS_WAKEUP(%edi), %ebx +	cmpl	$0, WRITERS_QUEUED(%edi) +	jne	0f + +	/* If also no readers waiting nothing to do.  */ +	cmpl	$0, READERS_QUEUED(%edi) +	je	6f + +	movl	$0x7fffffff, %edx +	leal	READERS_WAKEUP(%edi), %ebx + +0:	addl	$1, (%ebx) +	LOCK +#if MUTEX == 0 +	subl	$1, (%edi) +#else +	subl	$1, MUTEX(%edi) +#endif +	jne	7f + +8: +#ifdef __ASSUME_PRIVATE_FUTEX +	movzbl	PSHARED(%edi), %ecx +	xorl	$FUTEX_PRIVATE_FLAG|FUTEX_WAKE, %ecx +#else +	movzbl	PSHARED(%edi), %ecx +	orl	$FUTEX_WAKE, %ecx +	xorl	%gs:PRIVATE_FUTEX, %ecx +#endif +	movl	$SYS_futex, %eax +	ENTER_KERNEL + +	xorl	%eax, %eax +	popl	%edi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%edi) +	popl	%ebx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebx) +	ret + +	cfi_adjust_cfa_offset(8) +	cfi_offset(%ebx, -8) +	cfi_offset(%edi, -12) +	.align	16 +6:	LOCK +#if MUTEX == 0 +	subl	$1, (%edi) +#else +	subl	$1, MUTEX(%edi) +#endif +	jne	3f + +4:	xorl	%eax, %eax +	popl	%edi +	popl	%ebx +	ret + +1: +#if MUTEX == 0 +	movl	%edi, %edx +#else +	leal	MUTEX(%edi), %edx +#endif +	movzbl	PSHARED(%edi), %ecx +	call	__lll_lock_wait +	jmp	2b + +3: +#if MUTEX == 0 +	movl	%edi, %eax +#else +	leal	MUTEX(%edi), %eax +#endif +	movzbl	PSHARED(%edi), %ecx +	call	__lll_unlock_wake +	jmp	4b + +7: +#if MUTEX == 0 +	movl	%edi, %eax +#else +	leal	MUTEX(%edi), %eax +#endif +	movzbl	PSHARED(%edi), %ecx +	call	__lll_unlock_wake +	jmp	8b +	cfi_endproc +	.size	__pthread_rwlock_unlock,.-__pthread_rwlock_unlock + +	.globl	pthread_rwlock_unlock +pthread_rwlock_unlock = __pthread_rwlock_unlock + +	.globl	__pthread_rwlock_unlock_internal +__pthread_rwlock_unlock_internal = __pthread_rwlock_unlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S new file mode 100644 index 000000000..5c96d900b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S @@ -0,0 +1,186 @@ +/* Copyright (C) 2002, 2003, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <bits/kernel-features.h> +#include <tls.h> + + +	.text + +	.globl	__pthread_rwlock_wrlock +	.type	__pthread_rwlock_wrlock,@function +	.protected	__pthread_rwlock_wrlock +	.align	16 +__pthread_rwlock_wrlock: +	cfi_startproc +	pushl	%esi +	cfi_adjust_cfa_offset(4) +	pushl	%ebx +	cfi_adjust_cfa_offset(4) +	cfi_offset(%esi, -8) +	cfi_offset(%ebx, -12) + +	xorl	%esi, %esi +	movl	12(%esp), %ebx + +	/* Get the lock.  */ +	movl	$1, %edx +	xorl	%eax, %eax +	LOCK +#if MUTEX == 0 +	cmpxchgl %edx, (%ebx) +#else +	cmpxchgl %edx, MUTEX(%ebx) +#endif +	jnz	1f + +2:	movl	WRITER(%ebx), %eax +	testl	%eax, %eax +	jne	14f +	cmpl	$0, NR_READERS(%ebx) +	je	5f + +3:	addl	$1, WRITERS_QUEUED(%ebx) +	je	4f + +	movl	WRITERS_WAKEUP(%ebx), %edx + +	LOCK +#if MUTEX == 0 +	subl	$1, (%ebx) +#else +	subl	$1, MUTEX(%ebx) +#endif +	jne	10f + +11: +#ifdef __ASSUME_PRIVATE_FUTEX +	movzbl	PSHARED(%ebx), %ecx +	xorl	$FUTEX_PRIVATE_FLAG|FUTEX_WAIT, %ecx +#else +	movzbl	PSHARED(%ebx), %ecx +# if FUTEX_WAIT != 0 +	orl	$FUTEX_WAIT, %ecx +# endif +	xorl	%gs:PRIVATE_FUTEX, %ecx +#endif +	addl	$WRITERS_WAKEUP, %ebx +	movl	$SYS_futex, %eax +	ENTER_KERNEL + +	subl	$WRITERS_WAKEUP, %ebx + +	/* Reget the lock.  */ +	movl	$1, %edx +	xorl	%eax, %eax +	LOCK +#if MUTEX == 0 +	cmpxchgl %edx, (%ebx) +#else +	cmpxchgl %edx, MUTEX(%ebx) +#endif +	jnz	12f + +13:	subl	$1, WRITERS_QUEUED(%ebx) +	jmp	2b + +5:	xorl	%edx, %edx +	movl	%gs:TID, %eax +	movl	%eax, WRITER(%ebx) +9:	LOCK +#if MUTEX == 0 +	subl	$1, (%ebx) +#else +	subl	$1, MUTEX(%ebx) +#endif +	jne	6f +7: + +	movl	%edx, %eax +	popl	%ebx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebx) +	popl	%esi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%esi) +	ret + +	cfi_adjust_cfa_offset(8) +	cfi_offset(%esi, -8) +	cfi_offset(%ebx, -12) +1: +#if MUTEX == 0 +	movl	%ebx, %edx +#else +	leal	MUTEX(%ebx), %edx +#endif +	movzbl	PSHARED(%ebx), %ecx +	call	__lll_lock_wait +	jmp	2b + +14:	cmpl	%gs:TID	, %eax +	jne	3b +	movl	$EDEADLK, %edx +	jmp	9b + +6: +#if MUTEX == 0 +	movl	%ebx, %eax +#else +	leal	MUTEX(%ebx), %eax +#endif +	movzbl	PSHARED(%ebx), %ecx +	call	__lll_unlock_wake +	jmp	7b + +4:	subl	$1, WRITERS_QUEUED(%ebx) +	movl	$EAGAIN, %edx +	jmp	9b + +10: +#if MUTEX == 0 +	movl	%ebx, %eax +#else +	leal	MUTEX(%ebx), %eax +#endif +	movzbl	PSHARED(%ebx), %ecx +	call	__lll_unlock_wake +	jmp	11b + +12: +#if MUTEX == 0 +	movl	%ebx, %edx +#else +	leal	MUTEX(%ebx), %edx +#endif +	movzbl	PSHARED(%ebx), %ecx +	call	__lll_lock_wait +	jmp	13b +	cfi_endproc +	.size	__pthread_rwlock_wrlock,.-__pthread_rwlock_wrlock + +	.globl	pthread_rwlock_wrlock +pthread_rwlock_wrlock = __pthread_rwlock_wrlock + +	.globl	__pthread_rwlock_wrlock_internal +__pthread_rwlock_wrlock_internal = __pthread_rwlock_wrlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_post.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_post.S new file mode 100644 index 000000000..b077a20ca --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_post.S @@ -0,0 +1,142 @@ +/* Copyright (C) 2002, 2003, 2005, 2007, 2008 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <structsem.h> +#include <lowlevellock.h> + + +	.text + +	.globl	__new_sem_post +	.type	__new_sem_post,@function +	.align	16 +__new_sem_post: +	cfi_startproc +	pushl	%ebx +	cfi_adjust_cfa_offset(4) +	cfi_offset(%ebx, -8) + +	movl	8(%esp), %ebx + +#if VALUE == 0 +	movl	(%ebx), %eax +#else +	movl	VALUE(%ebx), %eax +#endif +0:	cmpl	$SEM_VALUE_MAX, %eax +	je	3f +	leal	1(%eax), %edx +	LOCK +#if VALUE == 0 +	cmpxchgl %edx, (%ebx) +#else +	cmpxchgl %edx, VALUE(%ebx) +#endif +	jnz	0b + +	cmpl	$0, NWAITERS(%ebx) +	je	2f + +	movl	$FUTEX_WAKE, %ecx +	orl	PRIVATE(%ebx), %ecx +	movl	$1, %edx +	movl	$SYS_futex, %eax +	ENTER_KERNEL + +	testl	%eax, %eax +	js	1f + +2:	xorl	%eax, %eax +	popl	%ebx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebx) +	ret + +	cfi_adjust_cfa_offset(4) +	cfi_offset(%ebx, -8) +1: +#ifdef __PIC__ +	call	__x86.get_pc_thunk.bx +#else +	movl	$4f, %ebx +4: +#endif +	addl	$_GLOBAL_OFFSET_TABLE_, %ebx +#if USE___THREAD +# ifdef NO_TLS_DIRECT_SEG_REFS +	movl	errno@gotntpoff(%ebx), %edx +	addl	%gs:0, %edx +	movl	$EINVAL, (%edx) +# else +	movl	errno@gotntpoff(%ebx), %edx +	movl	$EINVAL, %gs:(%edx) +# endif +#else +	call	__errno_location@plt +	movl	$EINVAL, (%eax) +#endif + +	orl	$-1, %eax +	popl	%ebx +	ret + +3: +#ifdef __PIC__ +	call	__x86.get_pc_thunk.bx +#else +	movl	$5f, %ebx +5: +#endif +	addl	$_GLOBAL_OFFSET_TABLE_, %ebx +#if USE___THREAD +# ifdef NO_TLS_DIRECT_SEG_REFS +	movl	errno@gotntpoff(%ebx), %edx +	addl	%gs:0, %edx +	movl	$EOVERFLOW, (%edx) +# else +	movl	errno@gotntpoff(%ebx), %edx +	movl	$EOVERFLOW, %gs:(%edx) +# endif +#else +	call	__errno_location@plt +	movl	$EOVERFLOW, (%eax) +#endif + +	orl	$-1, %eax +	popl	%ebx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(%ebx) +	ret +	cfi_endproc +	.size	__new_sem_post,.-__new_sem_post +weak_alias(__new_sem_post, sem_post) + + +#ifdef __PIC__ +	.section .gnu.linkonce.t.__x86.get_pc_thunk.bx,"ax",@progbits +	.globl	__x86.get_pc_thunk.bx +	.hidden	__x86.get_pc_thunk.bx +	.type	__x86.get_pc_thunk.bx,@function +__x86.get_pc_thunk.bx: +	movl (%esp), %ebx; +	ret +	.size	__x86.get_pc_thunk.bx,.-__x86.get_pc_thunk.bx +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S new file mode 100644 index 000000000..a1e3225cb --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S @@ -0,0 +1,329 @@ +/* Copyright (C) 2002, 2003, 2004, 2005, 2007, 2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <structsem.h> +#include <lowlevellock.h> + + +#if VALUE != 0 +# error "code needs to be rewritten for VALUE != 0" +#endif + + +	.text + +	.globl	sem_timedwait +	.type	sem_timedwait,@function +	.align	16 +sem_timedwait: +.LSTARTCODE: +	movl	4(%esp), %ecx + +	movl	(%ecx), %eax +2:	testl	%eax, %eax +	je	1f + +	leal	-1(%eax), %edx +	LOCK +	cmpxchgl %edx, (%ecx) +	jne	2b + +	xorl	%eax, %eax +	ret + +	/* Check whether the timeout value is valid.  */ +1:	pushl	%esi +.Lpush_esi: +	pushl	%edi +.Lpush_edi: +	pushl	%ebx +.Lpush_ebx: +	subl	$12, %esp +.Lsub_esp: + +	movl	32(%esp), %edi + +	/* Check for invalid nanosecond field.  */ +	cmpl	$1000000000, 4(%edi) +	movl	$EINVAL, %esi +	jae	6f + +	LOCK +	incl	NWAITERS(%ecx) + +7:	xorl	%ecx, %ecx +	movl	%esp, %ebx +	movl	%ecx, %edx +	movl	$__NR_gettimeofday, %eax +	ENTER_KERNEL + +	/* Compute relative timeout.  */ +	movl	4(%esp), %eax +	movl	$1000, %edx +	mul	%edx		/* Milli seconds to nano seconds.  */ +	movl	(%edi), %ecx +	movl	4(%edi), %edx +	subl	(%esp), %ecx +	subl	%eax, %edx +	jns	5f +	addl	$1000000000, %edx +	subl	$1, %ecx +5:	testl	%ecx, %ecx +	movl	$ETIMEDOUT, %esi +	js	6f		/* Time is already up.  */ + +	movl	%ecx, (%esp)	/* Store relative timeout.  */ +	movl	%edx, 4(%esp) + +.LcleanupSTART: +	call	__pthread_enable_asynccancel +	movl	%eax, 8(%esp) + +	movl	28(%esp), %ebx	/* Load semaphore address.  */ +#if FUTEX_WAIT == 0 +	movl	PRIVATE(%ebx), %ecx +#else +	movl	$FUTEX_WAIT, %ecx +	orl	PRIVATE(%ebx), %ecx +#endif +	movl	%esp, %esi +	xorl	%edx, %edx +	movl	$SYS_futex, %eax +	ENTER_KERNEL +	movl	%eax, %esi + +	movl	8(%esp), %eax +	call	__pthread_disable_asynccancel +.LcleanupEND: + +	testl	%esi, %esi +	je	9f +	cmpl	$-EWOULDBLOCK, %esi +	jne	3f + +9:	movl	(%ebx), %eax +8:	testl	%eax, %eax +	je	7b + +	leal	-1(%eax), %ecx +	LOCK +	cmpxchgl %ecx, (%ebx) +	jne	8b + +	xorl	%eax, %eax + +	LOCK +	decl	NWAITERS(%ebx) + +10:	addl	$12, %esp +.Ladd_esp: +	popl	%ebx +.Lpop_ebx: +	popl	%edi +.Lpop_edi: +	popl	%esi +.Lpop_esi: +	ret + +.Lafter_ret: +3:	negl	%esi +6: +#ifdef __PIC__ +	call	__x86.get_pc_thunk.bx +#else +	movl	$4f, %ebx +4: +#endif +	addl	$_GLOBAL_OFFSET_TABLE_, %ebx +#if USE___THREAD +# ifdef NO_TLS_DIRECT_SEG_REFS +	movl	errno@gotntpoff(%ebx), %edx +	addl	%gs:0, %edx +	movl	%esi, (%edx) +# else +	movl	errno@gotntpoff(%ebx), %edx +	movl	%esi, %gs:(%edx) +# endif +#else +	call	__errno_location@plt +	movl	%esi, (%eax) +#endif + +	movl	28(%esp), %ebx	/* Load semaphore address.  */ +	orl	$-1, %eax +	jmp	10b +	.size	sem_timedwait,.-sem_timedwait + + +	.type	sem_wait_cleanup,@function +sem_wait_cleanup: +	LOCK +	decl	NWAITERS(%ebx) +	movl	%eax, (%esp) +.LcallUR: +	call	_Unwind_Resume@PLT +	hlt +.LENDCODE: +	.size	sem_wait_cleanup,.-sem_wait_cleanup + + +	.section .gcc_except_table,"a",@progbits +.LexceptSTART: +	.byte	0xff				# @LPStart format (omit) +	.byte	0xff				# @TType format (omit) +	.byte	0x01				# call-site format +						# DW_EH_PE_uleb128 +	.uleb128 .Lcstend-.Lcstbegin +.Lcstbegin: +	.uleb128 .LcleanupSTART-.LSTARTCODE +	.uleb128 .LcleanupEND-.LcleanupSTART +	.uleb128 sem_wait_cleanup-.LSTARTCODE +	.uleb128  0 +	.uleb128 .LcallUR-.LSTARTCODE +	.uleb128 .LENDCODE-.LcallUR +	.uleb128 0 +	.uleb128  0 +.Lcstend: + + +	.section .eh_frame,"a",@progbits +.LSTARTFRAME: +	.long	.LENDCIE-.LSTARTCIE		# Length of the CIE. +.LSTARTCIE: +	.long	0				# CIE ID. +	.byte	1				# Version number. +#ifdef SHARED +	.string	"zPLR"				# NUL-terminated augmentation +						# string. +#else +	.string	"zPL"				# NUL-terminated augmentation +						# string. +#endif +	.uleb128 1				# Code alignment factor. +	.sleb128 -4				# Data alignment factor. +	.byte	8				# Return address register +						# column. +#ifdef SHARED +	.uleb128 7				# Augmentation value length. +	.byte	0x9b				# Personality: DW_EH_PE_pcrel +						# + DW_EH_PE_sdata4 +						# + DW_EH_PE_indirect +	.long	DW.ref.__gcc_personality_v0-. +	.byte	0x1b				# LSDA Encoding: DW_EH_PE_pcrel +						# + DW_EH_PE_sdata4. +	.byte	0x1b				# FDE Encoding: DW_EH_PE_pcrel +						# + DW_EH_PE_sdata4. +#else +	.uleb128 6				# Augmentation value length. +	.byte	0x0				# Personality: absolute +	.long	__gcc_personality_v0 +	.byte	0x0				# LSDA Encoding: absolute +#endif +	.byte 0x0c				# DW_CFA_def_cfa +	.uleb128 4 +	.uleb128 4 +	.byte	0x88				# DW_CFA_offset, column 0x10 +	.uleb128 1 +	.align 4 +.LENDCIE: + +	.long	.LENDFDE-.LSTARTFDE		# Length of the FDE. +.LSTARTFDE: +	.long	.LSTARTFDE-.LSTARTFRAME		# CIE pointer. +#ifdef SHARED +	.long	.LSTARTCODE-.			# PC-relative start address +						# of the code. +#else +	.long	.LSTARTCODE			# Start address of the code. +#endif +	.long	.LENDCODE-.LSTARTCODE		# Length of the code. +	.uleb128 4				# Augmentation size +#ifdef SHARED +	.long	.LexceptSTART-. +#else +	.long	.LexceptSTART +#endif + +	.byte	4				# DW_CFA_advance_loc4 +	.long	.Lpush_esi-.LSTARTCODE +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 8 +	.byte   0x86				# DW_CFA_offset %esi +	.uleb128 2 +	.byte	4				# DW_CFA_advance_loc4 +	.long	.Lpush_edi-.Lpush_esi +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 12 +	.byte   0x87				# DW_CFA_offset %edi +	.uleb128 3 +	.byte	4				# DW_CFA_advance_loc4 +	.long	.Lpush_ebx-.Lpush_edi +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 16 +	.byte   0x83				# DW_CFA_offset %ebx +	.uleb128 4 +	.byte	4				# DW_CFA_advance_loc4 +	.long	.Lsub_esp-.Lpush_ebx +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 28 +	.byte	4				# DW_CFA_advance_loc4 +	.long	.Ladd_esp-.Lsub_esp +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 16 +	.byte	4				# DW_CFA_advance_loc4 +	.long	.Lpop_ebx-.Ladd_esp +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 12 +	.byte	0xc3				# DW_CFA_restore %ebx +	.byte	4				# DW_CFA_advance_loc4 +	.long	.Lpop_edi-.Lpop_ebx +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 8 +	.byte	0xc7				# DW_CFA_restore %edi +	.byte	4				# DW_CFA_advance_loc4 +	.long	.Lpop_esi-.Lpop_edi +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 4 +	.byte	0xc6				# DW_CFA_restore %esi +	.byte	4				# DW_CFA_advance_loc4 +	.long	.Lafter_ret-.Lpop_esi +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 28 +	.byte   0x86				# DW_CFA_offset %esi +	.uleb128 2 +	.byte   0x87				# DW_CFA_offset %edi +	.uleb128 3 +	.byte   0x83				# DW_CFA_offset %ebx +	.uleb128 4 +	.align	4 +.LENDFDE: + + +#ifdef SHARED +	.hidden	DW.ref.__gcc_personality_v0 +	.weak	DW.ref.__gcc_personality_v0 +	.section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits +	.align	4 +	.type	DW.ref.__gcc_personality_v0, @object +	.size	DW.ref.__gcc_personality_v0, 4 +DW.ref.__gcc_personality_v0: +	.long	__gcc_personality_v0 +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S new file mode 100644 index 000000000..dad96858f --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S @@ -0,0 +1,79 @@ +/* Copyright (C) 2002, 2003, 2005, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <lowlevellock.h> + +	.text + +	.globl	__new_sem_trywait +	.type	__new_sem_trywait,@function +	.align	16 +__new_sem_trywait: +	movl	4(%esp), %ecx + +	movl	(%ecx), %eax +2:	testl	%eax, %eax +	jz	1f + +	leal	-1(%eax), %edx +	LOCK +	cmpxchgl %edx, (%ecx) +	jne	2b +	xorl	%eax, %eax +	ret + +1: +#ifdef __PIC__ +	call	__x86.get_pc_thunk.cx +#else +	movl	$3f, %ecx +3: +#endif +	addl	$_GLOBAL_OFFSET_TABLE_, %ecx +#if USE___THREAD +# ifdef NO_TLS_DIRECT_SEG_REFS +	movl	errno@gotntpoff(%ecx), %edx +	addl	%gs:0, %edx +	movl	$EAGAIN, (%edx) +# else +	movl	errno@gotntpoff(%ecx), %edx +	movl	$EAGAIN, %gs:(%edx) +# endif +#else +	call	__errno_location@plt +	movl	$EAGAIN, (%eax) +#endif +	orl	$-1, %eax +	ret +	.size	__new_sem_trywait,.-__new_sem_trywait +weak_alias(__new_sem_trywait, sem_trywait) + + +#ifdef __PIC__ +	.section .gnu.linkonce.t.__x86.get_pc_thunk.cx,"ax",@progbits +	.globl	__x86.get_pc_thunk.cx +	.hidden	__x86.get_pc_thunk.cx +	.type	__x86.get_pc_thunk.cx,@function +__x86.get_pc_thunk.cx: +	movl (%esp), %ecx; +	ret +	.size	__x86.get_pc_thunk.cx,.-__x86.get_pc_thunk.cx +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_wait.S new file mode 100644 index 000000000..b1c32ee4d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_wait.S @@ -0,0 +1,269 @@ +/* Copyright (C) 2002, 2003, 2005, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <structsem.h> +#include <lowlevellock.h> + + +#if VALUE != 0 +# error "code needs to be rewritten for VALUE != 0" +#endif + +	.text + +	.globl	__new_sem_wait +	.type	__new_sem_wait,@function +	.align	16 +__new_sem_wait: +.LSTARTCODE: +	pushl	%ebx +.Lpush_ebx: +	pushl	%esi +.Lpush_esi: +	subl	$4, %esp +.Lsub_esp: + +	movl	16(%esp), %ebx + +	movl	(%ebx), %eax +2:	testl	%eax, %eax +	je	1f + +	leal	-1(%eax), %edx +	LOCK +	cmpxchgl %edx, (%ebx) +	jne	2b +7:	xorl	%eax, %eax + +9:	movl	4(%esp), %esi +	movl	8(%esp), %ebx +	addl	$12, %esp +.Ladd_esp: +	ret + +.Lafter_ret: +1:	LOCK +	incl	NWAITERS(%ebx) + +.LcleanupSTART: +6:	call	__pthread_enable_asynccancel +	movl	%eax, (%esp) + +#if FUTEX_WAIT == 0 +	movl	PRIVATE(%ebx), %ecx +#else +	movl	$FUTEX_WAIT, %ecx +	orl	PRIVATE(%ebx), %ecx +#endif +	xorl	%esi, %esi +	xorl	%edx, %edx +	movl	$SYS_futex, %eax +	ENTER_KERNEL +	movl	%eax, %esi + +	movl	(%esp), %eax +	call	__pthread_disable_asynccancel +.LcleanupEND: + +	testl	%esi, %esi +	je	3f +	cmpl	$-EWOULDBLOCK, %esi +	jne	4f + +3: +	movl	(%ebx), %eax +5:	testl	%eax, %eax +	je	6b + +	leal	-1(%eax), %edx +	LOCK +	cmpxchgl %edx, (%ebx) +	jne	5b + +	LOCK +	decl	NWAITERS(%ebx) +	jmp	7b + +4:	LOCK +	decl	NWAITERS(%ebx) + +	negl	%esi +#ifdef __PIC__ +	call	__x86.get_pc_thunk.bx +#else +	movl	$8f, %ebx +8: +#endif +	addl	$_GLOBAL_OFFSET_TABLE_, %ebx +#if USE___THREAD +# ifdef NO_TLS_DIRECT_SEG_REFS +	movl	errno@gotntpoff(%ebx), %edx +	addl	%gs:0, %edx +	movl	%esi, (%edx) +# else +	movl	errno@gotntpoff(%ebx), %edx +	movl	%esi, %gs:(%edx) +# endif +#else +	call	__errno_location@plt +	movl	%esi, (%eax) +#endif +	orl	$-1, %eax + +	jmp	9b +	.size	__new_sem_wait,.-__new_sem_wait +weak_alias(__new_sem_wait, sem_wait) + + +	.type	sem_wait_cleanup,@function +sem_wait_cleanup: +	LOCK +	decl	NWAITERS(%ebx) +	movl	%eax, (%esp) +.LcallUR: +	call	_Unwind_Resume@PLT +	hlt +.LENDCODE: +	.size	sem_wait_cleanup,.-sem_wait_cleanup + + +	.section .gcc_except_table,"a",@progbits +.LexceptSTART: +	.byte	0xff				# @LPStart format (omit) +	.byte	0xff				# @TType format (omit) +	.byte	0x01				# call-site format +						# DW_EH_PE_uleb128 +	.uleb128 .Lcstend-.Lcstbegin +.Lcstbegin: +	.uleb128 .LcleanupSTART-.LSTARTCODE +	.uleb128 .LcleanupEND-.LcleanupSTART +	.uleb128 sem_wait_cleanup-.LSTARTCODE +	.uleb128  0 +	.uleb128 .LcallUR-.LSTARTCODE +	.uleb128 .LENDCODE-.LcallUR +	.uleb128 0 +	.uleb128  0 +.Lcstend: + + +	.section .eh_frame,"a",@progbits +.LSTARTFRAME: +	.long	.LENDCIE-.LSTARTCIE		# Length of the CIE. +.LSTARTCIE: +	.long	0				# CIE ID. +	.byte	1				# Version number. +#ifdef SHARED +	.string	"zPLR"				# NUL-terminated augmentation +						# string. +#else +	.string	"zPL"				# NUL-terminated augmentation +						# string. +#endif +	.uleb128 1				# Code alignment factor. +	.sleb128 -4				# Data alignment factor. +	.byte	8				# Return address register +						# column. +#ifdef SHARED +	.uleb128 7				# Augmentation value length. +	.byte	0x9b				# Personality: DW_EH_PE_pcrel +						# + DW_EH_PE_sdata4 +						# + DW_EH_PE_indirect +	.long	DW.ref.__gcc_personality_v0-. +	.byte	0x1b				# LSDA Encoding: DW_EH_PE_pcrel +						# + DW_EH_PE_sdata4. +	.byte	0x1b				# FDE Encoding: DW_EH_PE_pcrel +						# + DW_EH_PE_sdata4. +#else +	.uleb128 6				# Augmentation value length. +	.byte	0x0				# Personality: absolute +	.long	__gcc_personality_v0 +	.byte	0x0				# LSDA Encoding: absolute +#endif +	.byte 0x0c				# DW_CFA_def_cfa +	.uleb128 4 +	.uleb128 4 +	.byte	0x88				# DW_CFA_offset, column 0x10 +	.uleb128 1 +	.align 4 +.LENDCIE: + +	.long	.LENDFDE-.LSTARTFDE		# Length of the FDE. +.LSTARTFDE: +	.long	.LSTARTFDE-.LSTARTFRAME		# CIE pointer. +#ifdef SHARED +	.long	.LSTARTCODE-.			# PC-relative start address +						# of the code. +#else +	.long	.LSTARTCODE			# Start address of the code. +#endif +	.long	.LENDCODE-.LSTARTCODE		# Length of the code. +	.uleb128 4				# Augmentation size +#ifdef SHARED +	.long	.LexceptSTART-. +#else +	.long	.LexceptSTART +#endif + +	.byte	4				# DW_CFA_advance_loc4 +	.long	.Lpush_ebx-.LSTARTCODE +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 8 +	.byte   0x83				# DW_CFA_offset %ebx +        .uleb128 2 +	.byte	4				# DW_CFA_advance_loc4 +	.long	.Lpush_esi-.Lpush_ebx +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 12 +	.byte   0x86				# DW_CFA_offset %esi +        .uleb128 3 +	.byte	4				# DW_CFA_advance_loc4 +	.long	.Lsub_esp-.Lpush_esi +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 16 +	.byte	4				# DW_CFA_advance_loc4 +	.long	.Ladd_esp-.Lsub_esp +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 4 +	.byte	0xc3				# DW_CFA_restore %ebx +	.byte	0xc6				# DW_CFA_restore %esi +	.byte	4				# DW_CFA_advance_loc4 +	.long	.Lafter_ret-.Ladd_esp +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 16 +	.byte   0x83				# DW_CFA_offset %ebx +        .uleb128 2 +	.byte   0x86				# DW_CFA_offset %esi +        .uleb128 3 +	.align	4 +.LENDFDE: + + +#ifdef SHARED +	.hidden	DW.ref.__gcc_personality_v0 +	.weak	DW.ref.__gcc_personality_v0 +	.section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits +	.align	4 +	.type	DW.ref.__gcc_personality_v0, @object +	.size	DW.ref.__gcc_personality_v0, 4 +DW.ref.__gcc_personality_v0: +	.long	__gcc_personality_v0 +#endif + diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/libc-lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/libc-lowlevellock.S new file mode 100644 index 000000000..f567c1d6d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/libc-lowlevellock.S @@ -0,0 +1 @@ +#include "../i486/libc-lowlevellock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevellock.S new file mode 100644 index 000000000..e60dea89e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevellock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/lowlevellock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelrobustlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelrobustlock.S new file mode 100644 index 000000000..f768e16a7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelrobustlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002, 2006 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/lowlevelrobustlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_barrier_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_barrier_wait.S new file mode 100644 index 000000000..6d20b9a95 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_barrier_wait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/pthread_barrier_wait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_broadcast.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_broadcast.S new file mode 100644 index 000000000..5e1024eab --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_broadcast.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/pthread_cond_broadcast.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_signal.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_signal.S new file mode 100644 index 000000000..da4e8cbab --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_signal.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/pthread_cond_signal.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_timedwait.S new file mode 100644 index 000000000..c0131555b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_timedwait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/pthread_cond_timedwait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_wait.S new file mode 100644 index 000000000..9b57fbaca --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_cond_wait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/pthread_cond_wait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_rdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_rdlock.S new file mode 100644 index 000000000..da2bc4704 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_rdlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/pthread_rwlock_rdlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedrdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedrdlock.S new file mode 100644 index 000000000..0f2ec168b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedrdlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/pthread_rwlock_timedrdlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedwrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedwrlock.S new file mode 100644 index 000000000..26501590a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_timedwrlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/pthread_rwlock_timedwrlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_unlock.S new file mode 100644 index 000000000..5515e4895 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_unlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/pthread_rwlock_unlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_wrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_wrlock.S new file mode 100644 index 000000000..04ac275f6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_rwlock_wrlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/pthread_rwlock_wrlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_post.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_post.S new file mode 100644 index 000000000..7317e1582 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_post.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/sem_post.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_timedwait.S new file mode 100644 index 000000000..f34539d56 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_timedwait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/sem_timedwait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_trywait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_trywait.S new file mode 100644 index 000000000..64145c2e3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_trywait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/sem_trywait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_wait.S new file mode 100644 index 000000000..b3d462125 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i586/sem_wait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/sem_wait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/libc-lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/libc-lowlevellock.S new file mode 100644 index 000000000..f567c1d6d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/libc-lowlevellock.S @@ -0,0 +1 @@ +#include "../i486/libc-lowlevellock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevellock.S new file mode 100644 index 000000000..e60dea89e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevellock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/lowlevellock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelrobustlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelrobustlock.S new file mode 100644 index 000000000..f768e16a7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelrobustlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002, 2006 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/lowlevelrobustlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_barrier_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_barrier_wait.S new file mode 100644 index 000000000..6d20b9a95 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_barrier_wait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/pthread_barrier_wait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_broadcast.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_broadcast.S new file mode 100644 index 000000000..5e1024eab --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_broadcast.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/pthread_cond_broadcast.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_signal.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_signal.S new file mode 100644 index 000000000..da4e8cbab --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_signal.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/pthread_cond_signal.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_timedwait.S new file mode 100644 index 000000000..07d481f37 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_timedwait.S @@ -0,0 +1,21 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#define HAVE_CMOV 1 +#include "../i486/pthread_cond_timedwait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_wait.S new file mode 100644 index 000000000..9b57fbaca --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_cond_wait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/pthread_cond_wait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_rdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_rdlock.S new file mode 100644 index 000000000..da2bc4704 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_rdlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/pthread_rwlock_rdlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedrdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedrdlock.S new file mode 100644 index 000000000..0f2ec168b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedrdlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/pthread_rwlock_timedrdlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedwrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedwrlock.S new file mode 100644 index 000000000..26501590a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_timedwrlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/pthread_rwlock_timedwrlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_unlock.S new file mode 100644 index 000000000..0894f0546 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_unlock.S @@ -0,0 +1,21 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#define HAVE_CMOV	1 +#include "../i486/pthread_rwlock_unlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_wrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_wrlock.S new file mode 100644 index 000000000..04ac275f6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_rwlock_wrlock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/pthread_rwlock_wrlock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_post.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_post.S new file mode 100644 index 000000000..7317e1582 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_post.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/sem_post.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_timedwait.S new file mode 100644 index 000000000..f34539d56 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_timedwait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/sem_timedwait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_trywait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_trywait.S new file mode 100644 index 000000000..64145c2e3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_trywait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/sem_trywait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_wait.S new file mode 100644 index 000000000..b3d462125 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i686/sem_wait.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "../i486/sem_wait.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h new file mode 100644 index 000000000..55add8b8e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h @@ -0,0 +1,584 @@ +/* Copyright (C) 2002-2004, 2006-2008, 2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H	1 + +#ifndef __ASSEMBLER__ +# include <time.h> +# include <sys/param.h> +# include <bits/pthreadtypes.h> +# include <bits/kernel-features.h> +# include <tcb-offsets.h> + +# ifndef LOCK_INSTR +#  ifdef UP +#   define LOCK_INSTR	/* nothing */ +#  else +#   define LOCK_INSTR "lock;" +#  endif +# endif +#else +# ifndef LOCK +#  ifdef UP +#   define LOCK +#  else +#   define LOCK lock +#  endif +# endif +#endif + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 +#define FUTEX_CMP_REQUEUE	4 +#define FUTEX_WAKE_OP		5 +#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 + +#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE	((4 << 24) | 1) + +/* 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))								      \ +   : ({ unsigned int __fl = ((private) ^ FUTEX_PRIVATE_FLAG);		      \ +	__asm__ ("andl %%gs:%P1, %0" : "+r" (__fl)				      \ +	     : "i" (offsetof (struct pthread, header.private_futex)));	      \ +	__fl | (fl); })) +# endif +#endif + +#ifndef __ASSEMBLER__ + +/* Initializer for compatibility lock.  */ +#define LLL_LOCK_INITIALIZER		(0) +#define LLL_LOCK_INITIALIZER_LOCKED	(1) +#define LLL_LOCK_INITIALIZER_WAITERS	(2) + + +#ifdef __PIC__ +# define LLL_EBX_LOAD	"xchgl %2, %%ebx\n" +# define LLL_EBX_REG	"D" +#else +# define LLL_EBX_LOAD +# define LLL_EBX_REG	"b" +#endif + +#ifdef I386_USE_SYSENTER +# ifdef SHARED +#  define LLL_ENTER_KERNEL	"call *%%gs:%P6\n\t" +# else +#  define LLL_ENTER_KERNEL	"call *_dl_sysinfo\n\t" +# endif +#else +# define LLL_ENTER_KERNEL	"int $0x80\n\t" +#endif + +/* Delay in spinlock loop.  */ +#define BUSY_WAIT_NOP	__asm__ ("rep; nop") + + +#define LLL_STUB_UNWIND_INFO_START \ +	".section	.eh_frame,\"a\",@progbits\n"		\ +"5:\t"	".long	7f-6f	# Length of Common Information Entry\n"	\ +"6:\t"	".long	0x0	# CIE Identifier Tag\n\t"		\ +	".byte	0x1	# CIE Version\n\t"			\ +	".ascii \"zR\\0\"	# CIE Augmentation\n\t"		\ +	".uleb128 0x1	# CIE Code Alignment Factor\n\t"	\ +	".sleb128 -4	# CIE Data Alignment Factor\n\t"	\ +	".byte	0x8	# CIE RA Column\n\t"			\ +	".uleb128 0x1	# Augmentation size\n\t"		\ +	".byte	0x1b	# FDE Encoding (pcrel sdata4)\n\t"	\ +	".byte	0xc	# DW_CFA_def_cfa\n\t"			\ +	".uleb128 0x4\n\t"					\ +	".uleb128 0x0\n\t"					\ +	".align 4\n"						\ +"7:\t"	".long	17f-8f	# FDE Length\n"				\ +"8:\t"	".long	8b-5b	# FDE CIE offset\n\t"			\ +	".long	1b-.	# FDE initial location\n\t"		\ +	".long	4b-1b	# FDE address range\n\t"		\ +	".uleb128 0x0	# Augmentation size\n\t"		\ +	".byte	0x16	# DW_CFA_val_expression\n\t"		\ +	".uleb128 0x8\n\t"					\ +	".uleb128 10f-9f\n"					\ +"9:\t"	".byte	0x78	# DW_OP_breg8\n\t"			\ +	".sleb128 3b-1b\n" +#define LLL_STUB_UNWIND_INFO_END \ +	".byte	0x16	# DW_CFA_val_expression\n\t"		\ +	".uleb128 0x8\n\t"					\ +	".uleb128 12f-11f\n"					\ +"11:\t"	".byte	0x78	# DW_OP_breg8\n\t"			\ +	".sleb128 3b-2b\n"					\ +"12:\t"	".byte	0x40 + (3b-2b-1) # DW_CFA_advance_loc\n\t"	\ +	".byte	0x16	# DW_CFA_val_expression\n\t"		\ +	".uleb128 0x8\n\t"					\ +	".uleb128 16f-13f\n"					\ +"13:\t"	".byte	0x78	# DW_OP_breg8\n\t"			\ +	".sleb128 15f-14f\n\t"					\ +	".byte	0x0d	# DW_OP_const4s\n"			\ +"14:\t"	".4byte	3b-.\n\t"					\ +	".byte	0x1c	# DW_OP_minus\n\t"			\ +	".byte	0x0d	# DW_OP_const4s\n"			\ +"15:\t"	".4byte	18f-.\n\t"					\ +	".byte	0x22	# DW_OP_plus\n"				\ +"16:\t"	".align 4\n"						\ +"17:\t"	".previous\n" + +/* Unwind info for +   1: lea ..., ... +   2: call ... +   3: jmp 18f +   4: +   snippet.  */ +#define LLL_STUB_UNWIND_INFO_3 \ +LLL_STUB_UNWIND_INFO_START					\ +"10:\t"	".byte	0x40 + (2b-1b) # DW_CFA_advance_loc\n\t"	\ +LLL_STUB_UNWIND_INFO_END + +/* Unwind info for +   1: lea ..., ... +   0: movl ..., ... +   2: call ... +   3: jmp 18f +   4: +   snippet.  */ +#define LLL_STUB_UNWIND_INFO_4 \ +LLL_STUB_UNWIND_INFO_START					\ +"10:\t"	".byte	0x40 + (0b-1b) # DW_CFA_advance_loc\n\t"	\ +	".byte	0x16	# DW_CFA_val_expression\n\t"		\ +	".uleb128 0x8\n\t"					\ +	".uleb128 20f-19f\n"					\ +"19:\t"	".byte	0x78	# DW_OP_breg8\n\t"			\ +	".sleb128 3b-0b\n"					\ +"20:\t"	".byte	0x40 + (2b-0b) # DW_CFA_advance_loc\n\t"	\ +LLL_STUB_UNWIND_INFO_END + + +#define lll_futex_wait(futex, val, private) \ +  lll_futex_timed_wait (futex, val, NULL, private) + + +#define lll_futex_timed_wait(futex, val, timeout, private) \ +  ({									      \ +    int __status;							      \ +    register __typeof (val) _val __asm__ ("edx") = (val);			      \ +    __asm__ __volatile (LLL_EBX_LOAD					      \ +		      LLL_ENTER_KERNEL					      \ +		      LLL_EBX_LOAD					      \ +		      : "=a" (__status)					      \ +		      : "0" (SYS_futex), LLL_EBX_REG (futex), "S" (timeout),  \ +			"c" (__lll_private_flag (FUTEX_WAIT, private)),	      \ +			"d" (_val), "i" (offsetof (tcbhead_t, sysinfo))	      \ +		      : "memory");					      \ +    __status;								      \ +  }) + + +#define lll_futex_wake(futex, nr, private) \ +  do {									      \ +    int __ignore;							      \ +    register __typeof (nr) _nr __asm__ ("edx") = (nr);			      \ +    __asm__ __volatile (LLL_EBX_LOAD					      \ +		      LLL_ENTER_KERNEL					      \ +		      LLL_EBX_LOAD					      \ +		      : "=a" (__ignore)					      \ +		      : "0" (SYS_futex), LLL_EBX_REG (futex),		      \ +			"c" (__lll_private_flag (FUTEX_WAKE, private)),	      \ +			"d" (_nr),					      \ +			"i" (0) /* phony, to align next arg's number */,      \ +			"i" (offsetof (tcbhead_t, sysinfo)));		      \ +  } while (0) + + +/* NB: in the lll_trylock macro we simply return the value in %eax +   after the cmpxchg instruction.  In case the operation succeded this +   value is zero.  In case the operation failed, the cmpxchg instruction +   has loaded the current value of the memory work which is guaranteed +   to be nonzero.  */ +#if defined NOT_IN_libc || defined UP +# define __lll_trylock_asm LOCK_INSTR "cmpxchgl %2, %1" +#else +# define __lll_trylock_asm "cmpl $0, %%gs:%P5\n\t" \ +			   "je 0f\n\t"					      \ +			   "lock\n"					      \ +			   "0:\tcmpxchgl %2, %1" +#endif + +#define lll_trylock(futex) \ +  ({ int ret;								      \ +     __asm__ __volatile (__lll_trylock_asm				      \ +		       : "=a" (ret), "=m" (futex)			      \ +		       : "r" (LLL_LOCK_INITIALIZER_LOCKED), "m" (futex),      \ +			 "0" (LLL_LOCK_INITIALIZER),			      \ +			 "i" (MULTIPLE_THREADS_OFFSET)			      \ +		       : "memory");					      \ +     ret; }) + +#define lll_robust_trylock(futex, id) \ +  ({ int ret;								      \ +     __asm__ __volatile (LOCK_INSTR "cmpxchgl %2, %1"			      \ +		       : "=a" (ret), "=m" (futex)			      \ +		       : "r" (id), "m" (futex),				      \ +			 "0" (LLL_LOCK_INITIALIZER)			      \ +		       : "memory");					      \ +     ret; }) + + +#define lll_cond_trylock(futex) \ +  ({ int ret;								      \ +     __asm__ __volatile (LOCK_INSTR "cmpxchgl %2, %1"			      \ +		       : "=a" (ret), "=m" (futex)			      \ +		       : "r" (LLL_LOCK_INITIALIZER_WAITERS),		      \ +			 "m" (futex), "0" (LLL_LOCK_INITIALIZER)	      \ +		       : "memory");					      \ +     ret; }) + +#if defined NOT_IN_libc || defined UP +# define __lll_lock_asm_start LOCK_INSTR "cmpxchgl %1, %2\n\t" +#else +# define __lll_lock_asm_start "cmpl $0, %%gs:%P6\n\t"			      \ +			      "je 0f\n\t"				      \ +			      "lock\n"					      \ +			      "0:\tcmpxchgl %1, %2\n\t" +#endif + +#define lll_lock(futex, private) \ +  (void)								      \ +    ({ int ignore1, ignore2;						      \ +       if (__builtin_constant_p (private) && (private) == LLL_PRIVATE)	      \ +	 __asm__ __volatile (__lll_lock_asm_start				      \ +			   "jnz _L_lock_%=\n\t"				      \ +			   ".subsection 1\n\t"				      \ +			   ".type _L_lock_%=,@function\n"		      \ +			   "_L_lock_%=:\n"				      \ +			   "1:\tleal %2, %%ecx\n"			      \ +			   "2:\tcall __lll_lock_wait_private\n" 	      \ +			   "3:\tjmp 18f\n"				      \ +			   "4:\t.size _L_lock_%=, 4b-1b\n\t"		      \ +			   ".previous\n"				      \ +			   LLL_STUB_UNWIND_INFO_3			      \ +			   "18:"					      \ +			   : "=a" (ignore1), "=c" (ignore2), "=m" (futex)     \ +			   : "0" (0), "1" (1), "m" (futex),		      \ +			     "i" (MULTIPLE_THREADS_OFFSET)		      \ +			   : "memory");					      \ +       else								      \ +	 {								      \ +	   int ignore3;							      \ +	   __asm__ __volatile (__lll_lock_asm_start			      \ +			     "jnz _L_lock_%=\n\t"			      \ +			     ".subsection 1\n\t"			      \ +			     ".type _L_lock_%=,@function\n"		      \ +			     "_L_lock_%=:\n"				      \ +			     "1:\tleal %2, %%edx\n"			      \ +			     "0:\tmovl %8, %%ecx\n"			      \ +			     "2:\tcall __lll_lock_wait\n"		      \ +			     "3:\tjmp 18f\n"				      \ +			     "4:\t.size _L_lock_%=, 4b-1b\n\t"		      \ +			     ".previous\n"				      \ +			     LLL_STUB_UNWIND_INFO_4			      \ +			     "18:"					      \ +			     : "=a" (ignore1), "=c" (ignore2),		      \ +			       "=m" (futex), "=&d" (ignore3) 		      \ +			     : "1" (1), "m" (futex),			      \ +			       "i" (MULTIPLE_THREADS_OFFSET), "0" (0),	      \ +			       "g" ((int) (private))			      \ +			     : "memory");				      \ +	 }								      \ +    }) + +#define lll_robust_lock(futex, id, private) \ +  ({ int __result, ignore1, ignore2;					      \ +     __asm__ __volatile (LOCK_INSTR "cmpxchgl %1, %2\n\t"			      \ +		       "jnz _L_robust_lock_%=\n\t"			      \ +		       ".subsection 1\n\t"				      \ +		       ".type _L_robust_lock_%=,@function\n"		      \ +		       "_L_robust_lock_%=:\n"				      \ +		       "1:\tleal %2, %%edx\n"				      \ +		       "0:\tmovl %7, %%ecx\n"				      \ +		       "2:\tcall __lll_robust_lock_wait\n"		      \ +		       "3:\tjmp 18f\n"					      \ +		       "4:\t.size _L_robust_lock_%=, 4b-1b\n\t"		      \ +		       ".previous\n"					      \ +		       LLL_STUB_UNWIND_INFO_4				      \ +		       "18:"						      \ +		       : "=a" (__result), "=c" (ignore1), "=m" (futex),	      \ +			 "=&d" (ignore2)				      \ +		       : "0" (0), "1" (id), "m" (futex), "g" ((int) (private))\ +		       : "memory");					      \ +     __result; }) + + +/* Special version of lll_lock which causes the unlock function to +   always wakeup waiters.  */ +#define lll_cond_lock(futex, private) \ +  (void)								      \ +    ({ int ignore1, ignore2, ignore3;					      \ +       __asm__ __volatile (LOCK_INSTR "cmpxchgl %1, %2\n\t"		      \ +			 "jnz _L_cond_lock_%=\n\t"			      \ +			 ".subsection 1\n\t"				      \ +			 ".type _L_cond_lock_%=,@function\n"		      \ +			 "_L_cond_lock_%=:\n"				      \ +			 "1:\tleal %2, %%edx\n"				      \ +			 "0:\tmovl %7, %%ecx\n"				      \ +			 "2:\tcall __lll_lock_wait\n"			      \ +			 "3:\tjmp 18f\n"				      \ +			 "4:\t.size _L_cond_lock_%=, 4b-1b\n\t"		      \ +			 ".previous\n"					      \ +			 LLL_STUB_UNWIND_INFO_4				      \ +			 "18:"						      \ +			 : "=a" (ignore1), "=c" (ignore2), "=m" (futex),      \ +			   "=&d" (ignore3)				      \ +			 : "0" (0), "1" (2), "m" (futex), "g" ((int) (private))\ +			 : "memory");					      \ +    }) + + +#define lll_robust_cond_lock(futex, id, private) \ +  ({ int __result, ignore1, ignore2;					      \ +     __asm__ __volatile (LOCK_INSTR "cmpxchgl %1, %2\n\t"			      \ +		       "jnz _L_robust_cond_lock_%=\n\t"			      \ +		       ".subsection 1\n\t"				      \ +		       ".type _L_robust_cond_lock_%=,@function\n"	      \ +		       "_L_robust_cond_lock_%=:\n"			      \ +		       "1:\tleal %2, %%edx\n"				      \ +		       "0:\tmovl %7, %%ecx\n"				      \ +		       "2:\tcall __lll_robust_lock_wait\n"		      \ +		       "3:\tjmp 18f\n"					      \ +		       "4:\t.size _L_robust_cond_lock_%=, 4b-1b\n\t"	      \ +		       ".previous\n"					      \ +		       LLL_STUB_UNWIND_INFO_4				      \ +		       "18:"						      \ +		       : "=a" (__result), "=c" (ignore1), "=m" (futex),	      \ +			 "=&d" (ignore2)				      \ +		       : "0" (0), "1" (id | FUTEX_WAITERS), "m" (futex),      \ +			 "g" ((int) (private))				      \ +		       : "memory");					      \ +     __result; }) + + +#define lll_timedlock(futex, timeout, private) \ +  ({ int __result, ignore1, ignore2, ignore3;				      \ +     __asm__ __volatile (LOCK_INSTR "cmpxchgl %1, %3\n\t"			      \ +		       "jnz _L_timedlock_%=\n\t"			      \ +		       ".subsection 1\n\t"				      \ +		       ".type _L_timedlock_%=,@function\n"		      \ +		       "_L_timedlock_%=:\n"				      \ +		       "1:\tleal %3, %%ecx\n"				      \ +		       "0:\tmovl %8, %%edx\n"				      \ +		       "2:\tcall __lll_timedlock_wait\n"		      \ +		       "3:\tjmp 18f\n"					      \ +		       "4:\t.size _L_timedlock_%=, 4b-1b\n\t"		      \ +		       ".previous\n"					      \ +		       LLL_STUB_UNWIND_INFO_4				      \ +		       "18:"						      \ +		       : "=a" (__result), "=c" (ignore1), "=&d" (ignore2),      \ +			 "=m" (futex), "=S" (ignore3)			      \ +		       : "0" (0), "1" (1), "m" (futex), "m" (timeout),	      \ +			 "4" ((int) (private))				      \ +		       : "memory");					      \ +     __result; }) + + +#define lll_robust_timedlock(futex, timeout, id, private) \ +  ({ int __result, ignore1, ignore2, ignore3;				      \ +     __asm__ __volatile (LOCK_INSTR "cmpxchgl %1, %3\n\t"			      \ +		       "jnz _L_robust_timedlock_%=\n\t"			      \ +		       ".subsection 1\n\t"				      \ +		       ".type _L_robust_timedlock_%=,@function\n"	      \ +		       "_L_robust_timedlock_%=:\n"			      \ +		       "1:\tleal %3, %%ecx\n"				      \ +		       "0:\tmovl %8, %%edx\n"				      \ +		       "2:\tcall __lll_robust_timedlock_wait\n"		      \ +		       "3:\tjmp 18f\n"					      \ +		       "4:\t.size _L_robust_timedlock_%=, 4b-1b\n\t"	      \ +		       ".previous\n"					      \ +		       LLL_STUB_UNWIND_INFO_4				      \ +		       "18:"						      \ +		       : "=a" (__result), "=c" (ignore1), "=&d" (ignore2),      \ +			 "=m" (futex), "=S" (ignore3)			      \ +		       : "0" (0), "1" (id), "m" (futex), "m" (timeout),	      \ +			 "4" ((int) (private))				      \ +		       : "memory");					      \ +     __result; }) + +#if defined NOT_IN_libc || defined UP +# define __lll_unlock_asm LOCK_INSTR "subl $1, %0\n\t" +#else +# define __lll_unlock_asm "cmpl $0, %%gs:%P3\n\t"			      \ +			  "je 0f\n\t"					      \ +			  "lock\n"					      \ +			  "0:\tsubl $1,%0\n\t" +#endif + +#define lll_unlock(futex, private) \ +  (void)								      \ +    ({ int ignore;							      \ +       if (__builtin_constant_p (private) && (private) == LLL_PRIVATE)	      \ +	 __asm__ __volatile (__lll_unlock_asm				      \ +			   "jne _L_unlock_%=\n\t"			      \ +			   ".subsection 1\n\t"				      \ +			   ".type _L_unlock_%=,@function\n"		      \ +			   "_L_unlock_%=:\n"				      \ +			   "1:\tleal %0, %%eax\n"			      \ +			   "2:\tcall __lll_unlock_wake_private\n"	      \ +			   "3:\tjmp 18f\n"				      \ +			   "4:\t.size _L_unlock_%=, 4b-1b\n\t"		      \ +			   ".previous\n"				      \ +			   LLL_STUB_UNWIND_INFO_3			      \ +			   "18:"					      \ +			   : "=m" (futex), "=&a" (ignore)		      \ +			   : "m" (futex), "i" (MULTIPLE_THREADS_OFFSET)	      \ +			   : "memory");					      \ +       else								      \ +	 {								      \ +	   int ignore2;							      \ +	   __asm__ __volatile (__lll_unlock_asm				      \ +			     "jne _L_unlock_%=\n\t"			      \ +			     ".subsection 1\n\t"			      \ +			     ".type _L_unlock_%=,@function\n"		      \ +			     "_L_unlock_%=:\n"				      \ +			     "1:\tleal %0, %%eax\n"			      \ +			     "0:\tmovl %5, %%ecx\n"			      \ +			     "2:\tcall __lll_unlock_wake\n"		      \ +			     "3:\tjmp 18f\n"				      \ +			     "4:\t.size _L_unlock_%=, 4b-1b\n\t"	      \ +			     ".previous\n"				      \ +			     LLL_STUB_UNWIND_INFO_4			      \ +			     "18:"					      \ +			     : "=m" (futex), "=&a" (ignore), "=&c" (ignore2)  \ +			     : "i" (MULTIPLE_THREADS_OFFSET), "m" (futex),    \ +			       "g" ((int) (private))			      \ +			     : "memory");				      \ +	 }								      \ +    }) + +#define lll_robust_unlock(futex, private) \ +  (void)								      \ +    ({ int ignore, ignore2;						      \ +       __asm__ __volatile (LOCK_INSTR "andl %3, %0\n\t"			      \ +			 "jne _L_robust_unlock_%=\n\t"			      \ +			 ".subsection 1\n\t"				      \ +			 ".type _L_robust_unlock_%=,@function\n"	      \ +			 "_L_robust_unlock_%=:\n\t"			      \ +			 "1:\tleal %0, %%eax\n"				      \ +			 "0:\tmovl %5, %%ecx\n"				      \ +			 "2:\tcall __lll_unlock_wake\n"			      \ +			 "3:\tjmp 18f\n"				      \ +			 "4:\t.size _L_robust_unlock_%=, 4b-1b\n\t"	      \ +			 ".previous\n"					      \ +			 LLL_STUB_UNWIND_INFO_4				      \ +			 "18:"						      \ +			 : "=m" (futex), "=&a" (ignore), "=&c" (ignore2)      \ +			 : "i" (FUTEX_WAITERS), "m" (futex),		      \ +			   "g" ((int) (private))			      \ +			 : "memory");					      \ +    }) + + +#define lll_robust_dead(futex, private) \ +  (void)								      \ +    ({ int __ignore;							      \ +       register int _nr __asm__ ("edx") = 1;				      \ +       __asm__ __volatile (LOCK_INSTR "orl %5, (%2)\n\t"			      \ +			 LLL_EBX_LOAD					      \ +			 LLL_ENTER_KERNEL				      \ +			 LLL_EBX_LOAD					      \ +			 : "=a" (__ignore)				      \ +			 : "0" (SYS_futex), LLL_EBX_REG (&(futex)),	      \ +			   "c" (__lll_private_flag (FUTEX_WAKE, private)),    \ +			   "d" (_nr), "i" (FUTEX_OWNER_DIED),		      \ +			   "i" (offsetof (tcbhead_t, sysinfo)));	      \ +    }) + +#define lll_islocked(futex) \ +  (futex != LLL_LOCK_INITIALIZER) + +/* The kernel notifies a process with uses CLONE_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. + +   The macro parameter must not have any side effect.  */ +#define lll_wait_tid(tid) \ +  do {									      \ +    int __ignore;							      \ +    register __typeof (tid) _tid __asm__ ("edx") = (tid);			      \ +    if (_tid != 0)							      \ +      __asm__ __volatile (LLL_EBX_LOAD					      \ +			"1:\tmovl %1, %%eax\n\t"			      \ +			LLL_ENTER_KERNEL				      \ +			"cmpl $0, (%%ebx)\n\t"				      \ +			"jne 1b\n\t"					      \ +			LLL_EBX_LOAD					      \ +			: "=&a" (__ignore)				      \ +			: "i" (SYS_futex), LLL_EBX_REG (&tid), "S" (0),	      \ +			  "c" (FUTEX_WAIT), "d" (_tid),			      \ +			  "i" (offsetof (tcbhead_t, sysinfo))		      \ +			: "memory");					      \ +  } while (0) + +extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime) +     __attribute__ ((regparm (2))) attribute_hidden; +#define lll_timedwait_tid(tid, abstime) \ +  ({									      \ +    int __result = 0;							      \ +    if (tid != 0)							      \ +      {									      \ +	if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)	      \ +	  __result = EINVAL;						      \ +	else								      \ +	  __result = __lll_timedwait_tid (&tid, abstime);		      \ +      }									      \ +    __result; }) + +#endif  /* !__ASSEMBLER__ */ + +#endif	/* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pt-__syscall_error.c b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pt-__syscall_error.c new file mode 100644 index 000000000..620640ad6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pt-__syscall_error.c @@ -0,0 +1 @@ +#include <../../../../../../../libc/sysdeps/linux/i386/__syscall_error.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pt-vfork.S new file mode 100644 index 000000000..aff926a8f --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pt-vfork.S @@ -0,0 +1,68 @@ +/* Copyright (C) 1999, 2002, 2004 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Andreas Schwab <schwab@gnu.org>. + +   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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#define _ERRNO_H	1 +#include <bits/errno.h> +#include <bits/kernel-features.h> +#include <tcb-offsets.h> + +/* Save the PID value.  */ +#define SAVE_PID \ +	movl	%gs:PID, %edx; 						      \ +	movl	%edx, %eax;						      \ +	negl	%eax;							      \ +	movl	%eax, %gs:PID + +/* Restore the old PID value in the parent.  */ +#define RESTORE_PID \ +	testl	%eax, %eax;						      \ +	je	1f;							      \ +	movl	%edx, %gs:PID;						      \ +1: + +/* Clone the calling process, but without copying the whole address space. +   The calling process is suspended until the new process exits or is +   replaced by a call to `execve'.  Return -1 for errors, 0 to the new process, +   and the process ID of the new process to the old process.  */ + +ENTRY (__vfork) +	/* Pop the return PC value into ECX.  */ +	popl	%ecx + +	SAVE_PID + +	/* Stuff the syscall number in EAX and enter into the kernel.  */ +	movl	$SYS_ify (vfork), %eax +	int	$0x80 + +	RESTORE_PID + +	/* Jump to the return PC.  Don't jump directly since this +	   disturbs the branch target cache.  Instead push the return +	   address back on the stack.  */ +	pushl	%ecx + +	cmpl	$-4095, %eax +	jae	SYSCALL_ERROR_LABEL	/* Branch forward if it failed.  */ +L(pseudo_end): +	ret +PSEUDO_END (__vfork) + +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_once.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_once.S new file mode 100644 index 000000000..7a2cbf464 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_once.S @@ -0,0 +1,197 @@ +/* Copyright (C) 2002, 2003, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <unwindbuf.h> +#include <sysdep.h> +#include <bits/kernel-features.h> +#include <lowlevellock.h> +#include <tls.h> + + +	.comm	__fork_generation, 4, 4 + +	.text + + +	.globl	__pthread_once +	.type	__pthread_once,@function +	.protected	__pthread_once +	.align	16 +	cfi_startproc +__pthread_once: +	movl	4(%esp), %ecx +	testl	$2, (%ecx) +	jz	1f +	xorl	%eax, %eax +	ret + +1:	pushl	%ebx +	cfi_adjust_cfa_offset (4) +	cfi_rel_offset (3, 0) +	pushl	%esi +	cfi_adjust_cfa_offset (4) +	cfi_rel_offset (6, 0) +	movl	%ecx, %ebx +	xorl	%esi, %esi + +	/* Not yet initialized or initialization in progress. +	   Get the fork generation counter now.  */ +6:	movl	(%ebx), %eax +#ifdef __PIC__ +	call	__x86.get_pc_thunk.cx +	addl	$_GLOBAL_OFFSET_TABLE_, %ecx +#endif + +5:	movl	%eax, %edx + +	testl	$2, %eax +	jnz	4f + +	andl	$3, %edx +#ifdef __PIC__ +	orl	__fork_generation@GOTOFF(%ecx), %edx +#else +	orl	__fork_generation, %edx +#endif +	orl	$1, %edx + +	LOCK +	cmpxchgl %edx, (%ebx) +	jnz	5b + +	/* Check whether another thread already runs the initializer.  */ +	testl	$1, %eax +	jz	3f	/* No -> do it.  */ + +	/* Check whether the initializer execution was interrupted +	   by a fork.  */ +	xorl	%edx, %eax +	testl	$0xfffffffc, %eax +	jnz	3f	/* Different for generation -> run initializer.  */ + +	/* Somebody else got here first.  Wait.  */ +#ifdef __ASSUME_PRIVATE_FUTEX +	movl	$FUTEX_WAIT|FUTEX_PRIVATE_FLAG, %ecx +#else +# if FUTEX_WAIT == 0 +	movl	%gs:PRIVATE_FUTEX, %ecx +# else +	movl	$FUTEX_WAIT, %ecx +	orl	%gs:PRIVATE_FUTEX, %ecx +# endif +#endif +	movl	$SYS_futex, %eax +	ENTER_KERNEL +	jmp	6b + +3:	/* Call the initializer function after setting up the +	   cancellation handler.  Note that it is not possible here +	   to use the unwind-based cleanup handling.  This would require +	   that the user-provided function and all the code it calls +	   is compiled with exceptions.  Unfortunately this cannot be +	   guaranteed.  */ +	subl	$UNWINDBUFSIZE+8, %esp +	cfi_adjust_cfa_offset (UNWINDBUFSIZE+8) +	movl	%ecx, %ebx		/* PIC register value.  */ + +	leal	8+UWJMPBUF(%esp), %eax +	movl	$0, 4(%esp) +	movl	%eax, (%esp) +	call	__sigsetjmp@PLT +	testl	%eax, %eax +	jne	7f + +	leal	8(%esp), %eax +	call	HIDDEN_JUMPTARGET(__pthread_register_cancel) + +	/* Call the user-provided initialization function.  */ +	call	*24+UNWINDBUFSIZE(%esp) + +	/* Pop the cleanup handler.  */ +	leal	8(%esp), %eax +	call	HIDDEN_JUMPTARGET(__pthread_unregister_cancel) +	addl	$UNWINDBUFSIZE+8, %esp +	cfi_adjust_cfa_offset (-UNWINDBUFSIZE-8) + +	/* Sucessful run of the initializer.  Signal that we are done.  */ +	movl	12(%esp), %ebx +	LOCK +	addl	$1, (%ebx) + +	/* Wake up all other threads.  */ +	movl	$0x7fffffff, %edx +#ifdef __ASSUME_PRIVATE_FUTEX +	movl	$FUTEX_WAKE|FUTEX_PRIVATE_FLAG, %ecx +#else +	movl	$FUTEX_WAKE, %ecx +	orl	%gs:PRIVATE_FUTEX, %ecx +#endif +	movl	$SYS_futex, %eax +	ENTER_KERNEL + +4:	popl	%esi +	cfi_adjust_cfa_offset (-4) +	cfi_restore (6) +	popl	%ebx +	cfi_adjust_cfa_offset (-4) +	cfi_restore (3) +	xorl	%eax, %eax +	ret + +7:	/* __sigsetjmp returned for the second time.  */ +	movl	20+UNWINDBUFSIZE(%esp), %ebx +	cfi_adjust_cfa_offset (UNWINDBUFSIZE+16) +	cfi_offset (3, -8) +	cfi_offset (6, -12) +	movl	$0, (%ebx) + +	movl	$0x7fffffff, %edx +#ifdef __ASSUME_PRIVATE_FUTEX +	movl	$FUTEX_WAKE|FUTEX_PRIVATE_FLAG, %ecx +#else +	movl	$FUTEX_WAKE, %ecx +	orl	%gs:PRIVATE_FUTEX, %ecx +#endif +	movl	$SYS_futex, %eax +	ENTER_KERNEL + +	leal	8(%esp), %eax +	call	HIDDEN_JUMPTARGET (__pthread_unwind_next) +	/* NOTREACHED */ +	hlt +	cfi_endproc +	.size	__pthread_once,.-__pthread_once + +	.globl	__pthread_once_internal +__pthread_once_internal = __pthread_once + +	.globl	pthread_once +pthread_once = __pthread_once + + +#ifdef __PIC__ +	.section .gnu.linkonce.t.__x86.get_pc_thunk.cx,"ax",@progbits +	.globl	__x86.get_pc_thunk.cx +	.hidden	__x86.get_pc_thunk.cx +	.type	__x86.get_pc_thunk.cx,@function +__x86.get_pc_thunk.cx: +	movl (%esp), %ecx; +	ret +	.size	__x86.get_pc_thunk.cx,.-__x86.get_pc_thunk.cx +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_init.c b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_init.c new file mode 100644 index 000000000..d36e5373d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_init.c @@ -0,0 +1 @@ +#include <sysdeps/i386/pthread_spin_init.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_unlock.S new file mode 100644 index 000000000..8bae0fd31 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_spin_unlock.S @@ -0,0 +1 @@ +#include <sysdeps/i386/pthread_spin_unlock.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/smp.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/smp.h new file mode 100644 index 000000000..f68a0c075 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/smp.h @@ -0,0 +1,56 @@ +/* Determine whether the host has multiple processors.  Linux version. +   Copyright (C) 1996, 2002, 2004, 2006 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 Library General Public License as +   published by the Free Software Foundation; either version 2 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 +   Library General Public License for more details. + +   You should have received a copy of the GNU Library General Public +   License along with the GNU C Library; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +#include <errno.h> +#include <fcntl.h> +#include <string.h> +#include <sys/utsname.h> +#include <not-cancel.h> + +/* Test whether the machine has more than one processor.  This is not the +   best test but good enough.  More complicated tests would require `malloc' +   which is not available at that time.  */ +static inline int +is_smp_system (void) +{ +  union +  { +    struct utsname uts; +    char buf[512]; +  } u; +  char *cp; + +  /* Try reading the number using `sysctl' first.  */ +  if (uname (&u.uts) == 0) +    cp = u.uts.version; +  else +    { +      /* This was not successful.  Now try reading the /proc filesystem.  */ +      int fd = open_not_cancel_2 ("/proc/sys/kernel/version", O_RDONLY); +      if (__builtin_expect (fd, 0) == -1 +	  || read_not_cancel (fd, u.buf, sizeof (u.buf)) <= 0) +	/* This also didn't work.  We give up and say it's a UP machine.  */ +	u.buf[0] = '\0'; + +      close_not_cancel_no_status (fd); +      cp = u.buf; +    } + +  return strstr (cp, "SMP") != NULL; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h new file mode 100644 index 000000000..cb8d6891c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h @@ -0,0 +1,155 @@ +/* Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Jakub Jelinek <jakub@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <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;								      \ +  ENTRY (name)								      \ +    cmpl $0, %gs:MULTIPLE_THREADS_OFFSET;				      \ +    jne L(pseudo_cancel);						      \ +  .type __##syscall_name##_nocancel,@function;				      \ +  .globl __##syscall_name##_nocancel;					      \ +  __##syscall_name##_nocancel:						      \ +    DO_CALL (syscall_name, args);					      \ +    cmpl $-4095, %eax;							      \ +    jae SYSCALL_ERROR_LABEL;						      \ +    ret;								      \ +  .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;	      \ +  L(pseudo_cancel):							      \ +    CENABLE								      \ +    SAVE_OLDTYPE_##args							      \ +    PUSHCARGS_##args							      \ +    DOCARGS_##args							      \ +    movl $SYS_ify (syscall_name), %eax;					      \ +    ENTER_KERNEL;							      \ +    POPCARGS_##args;							      \ +    POPSTATE_##args							      \ +    cmpl $-4095, %eax;							      \ +    jae SYSCALL_ERROR_LABEL;						      \ +  L(pseudo_end): + +# define SAVE_OLDTYPE_0	movl %eax, %ecx; +# define SAVE_OLDTYPE_1	SAVE_OLDTYPE_0 +# define SAVE_OLDTYPE_2	pushl %eax; cfi_adjust_cfa_offset (4); +# define SAVE_OLDTYPE_3	SAVE_OLDTYPE_2 +# define SAVE_OLDTYPE_4	SAVE_OLDTYPE_2 +# define SAVE_OLDTYPE_5	SAVE_OLDTYPE_2 +# define SAVE_OLDTYPE_6	SAVE_OLDTYPE_2 + +# define PUSHCARGS_0	/* No arguments to push.  */ +# define DOCARGS_0	/* No arguments to frob.  */ +# define POPCARGS_0	/* No arguments to pop.  */ +# define _PUSHCARGS_0	/* No arguments to push.  */ +# define _POPCARGS_0	/* No arguments to pop.  */ + +# define PUSHCARGS_1	movl %ebx, %edx; cfi_register (ebx, edx); PUSHCARGS_0 +# define DOCARGS_1	_DOARGS_1 (4) +# define POPCARGS_1	POPCARGS_0; movl %edx, %ebx; cfi_restore (ebx); +# define _PUSHCARGS_1	pushl %ebx; cfi_adjust_cfa_offset (4); \ +			cfi_rel_offset (ebx, 0); _PUSHCARGS_0 +# define _POPCARGS_1	_POPCARGS_0; popl %ebx; \ +			cfi_adjust_cfa_offset (-4); cfi_restore (ebx); + +# define PUSHCARGS_2	PUSHCARGS_1 +# define DOCARGS_2	_DOARGS_2 (12) +# define POPCARGS_2	POPCARGS_1 +# define _PUSHCARGS_2	_PUSHCARGS_1 +# define _POPCARGS_2	_POPCARGS_1 + +# define PUSHCARGS_3	_PUSHCARGS_2 +# define DOCARGS_3	_DOARGS_3 (20) +# define POPCARGS_3	_POPCARGS_3 +# define _PUSHCARGS_3	_PUSHCARGS_2 +# define _POPCARGS_3	_POPCARGS_2 + +# define PUSHCARGS_4	_PUSHCARGS_4 +# define DOCARGS_4	_DOARGS_4 (28) +# define POPCARGS_4	_POPCARGS_4 +# define _PUSHCARGS_4	pushl %esi; cfi_adjust_cfa_offset (4); \ +			cfi_rel_offset (esi, 0); _PUSHCARGS_3 +# define _POPCARGS_4	_POPCARGS_3; popl %esi; \ +			cfi_adjust_cfa_offset (-4); cfi_restore (esi); + +# define PUSHCARGS_5	_PUSHCARGS_5 +# define DOCARGS_5	_DOARGS_5 (36) +# define POPCARGS_5	_POPCARGS_5 +# define _PUSHCARGS_5	pushl %edi; cfi_adjust_cfa_offset (4); \ +			cfi_rel_offset (edi, 0); _PUSHCARGS_4 +# define _POPCARGS_5	_POPCARGS_4; popl %edi; \ +			cfi_adjust_cfa_offset (-4); cfi_restore (edi); + +# define PUSHCARGS_6	_PUSHCARGS_6 +# define DOCARGS_6	_DOARGS_6 (44) +# define POPCARGS_6	_POPCARGS_6 +# define _PUSHCARGS_6	pushl %ebp; cfi_adjust_cfa_offset (4); \ +			cfi_rel_offset (ebp, 0); _PUSHCARGS_5 +# define _POPCARGS_6	_POPCARGS_5; popl %ebp; \ +			cfi_adjust_cfa_offset (-4); cfi_restore (ebp); + +# ifdef IS_IN_libpthread +#  define CENABLE	call __pthread_enable_asynccancel; +#  define CDISABLE	call __pthread_disable_asynccancel +# elif !defined NOT_IN_libc +#  define CENABLE	call __libc_enable_asynccancel; +#  define CDISABLE	call __libc_disable_asynccancel +# elif defined IS_IN_librt +#  define CENABLE	call __librt_enable_asynccancel; +#  define CDISABLE	call __librt_disable_asynccancel +# else +#  error Unsupported library +# endif +# define POPSTATE_0 \ + pushl %eax; cfi_adjust_cfa_offset (4); movl %ecx, %eax; \ + CDISABLE; popl %eax; cfi_adjust_cfa_offset (-4); +# define POPSTATE_1	POPSTATE_0 +# define POPSTATE_2	xchgl (%esp), %eax; CDISABLE; popl %eax; \ +			cfi_adjust_cfa_offset (-4); +# define POPSTATE_3	POPSTATE_2 +# define POPSTATE_4	POPSTATE_3 +# define POPSTATE_5	POPSTATE_4 +# define POPSTATE_6	POPSTATE_5 + +# ifndef __ASSEMBLER__ +#  define SINGLE_THREAD_P \ +  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ +				   header.multiple_threads) == 0, 1) +# else +#  define SINGLE_THREAD_P cmpl $0, %gs:MULTIPLE_THREADS_OFFSET +# 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/libpthread/nptl/sysdeps/unix/sysv/linux/i386/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/vfork.S new file mode 100644 index 000000000..b39099af5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/vfork.S @@ -0,0 +1,38 @@ +/* Copyright (C) 1999,2002,2004,2006 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <tcb-offsets.h> + +/* Save the PID value.  */ +#define SAVE_PID \ +	movl	%gs:PID, %edx; 						      \ +	movl	%edx, %eax;						      \ +	negl	%eax;							      \ +	jne	1f;							      \ +	movl	$0x80000000, %eax;					      \ +1:	movl	%eax, %gs:PID + +/* Restore the old PID value in the parent.  */ +#define RESTORE_PID \ +	testl	%eax, %eax;						      \ +	je	1f;							      \ +	movl	%edx, %gs:PID;						      \ +1: + + +#include <libc/sysdeps/linux/i386/vfork.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/internaltypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/internaltypes.h new file mode 100644 index 000000000..3466c7fe5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/internaltypes.h @@ -0,0 +1,162 @@ +/* Copyright (C) 2002, 2003, 2004, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _INTERNALTYPES_H +#define _INTERNALTYPES_H	1 + +#include <stdint.h> +#include <sched.h> + +struct pthread_attr +{ +  /* Scheduler parameters and priority.  */ +  struct sched_param schedparam; +  int schedpolicy; +  /* Various flags like detachstate, scope, etc.  */ +  int flags; +  /* Size of guard area.  */ +  size_t guardsize; +  /* Stack handling.  */ +  void *stackaddr; +  size_t stacksize; +  /* Affinity map.  */ +  cpu_set_t *cpuset; +  size_t cpusetsize; +}; + +#define ATTR_FLAG_DETACHSTATE		0x0001 +#define ATTR_FLAG_NOTINHERITSCHED	0x0002 +#define ATTR_FLAG_SCOPEPROCESS		0x0004 +#define ATTR_FLAG_STACKADDR		0x0008 +#define ATTR_FLAG_OLDATTR		0x0010 +#define ATTR_FLAG_SCHED_SET		0x0020 +#define ATTR_FLAG_POLICY_SET		0x0040 + + +/* Mutex attribute data structure.  */ +struct pthread_mutexattr +{ +  /* Identifier for the kind of mutex. + +     Bit 31 is set if the mutex is to be shared between processes. + +     Bit 0 to 30 contain one of the PTHREAD_MUTEX_ values to identify +     the type of the mutex.  */ +  int mutexkind; +}; + + +/* Conditional variable attribute data structure.  */ +struct pthread_condattr +{ +  /* Combination of values: + +     Bit 0  : flag whether coditional variable will be shareable between +	      processes. + +     Bit 1-7: clock ID.  */ +  int value; +}; + + +/* The __NWAITERS field is used as a counter and to house the number +   of bits for other purposes.  COND_CLOCK_BITS is the number +   of bits needed to represent the ID of the clock.  COND_NWAITERS_SHIFT +   is the number of bits reserved for other purposes like the clock.  */ +#define COND_CLOCK_BITS		1 +#define COND_NWAITERS_SHIFT	1 + + +/* Read-write lock variable attribute data structure.  */ +struct pthread_rwlockattr +{ +  int lockkind; +  int pshared; +}; + + +/* Barrier data structure.  */ +struct pthread_barrier +{ +  unsigned int curr_event; +  int lock; +  unsigned int left; +  unsigned int init_count; +  int private; +}; + + +/* Barrier variable attribute data structure.  */ +struct pthread_barrierattr +{ +  int pshared; +}; + + +/* Thread-local data handling.  */ +struct pthread_key_struct +{ +  /* Sequence numbers.  Even numbers indicated vacant entries.  Note +     that zero is even.  We use uintptr_t to not require padding on +     32- and 64-bit machines.  On 64-bit machines it helps to avoid +     wrapping, too.  */ +  uintptr_t seq; + +  /* Destructor for the data.  */ +  void (*destr) (void *); +}; + +/* Check whether an entry is unused.  */ +#define KEY_UNUSED(p) (((p) & 1) == 0) +/* Check whether a key is usable.  We cannot reuse an allocated key if +   the sequence counter would overflow after the next destroy call. +   This would mean that we potentially free memory for a key with the +   same sequence.  This is *very* unlikely to happen, A program would +   have to create and destroy a key 2^31 times (on 32-bit platforms, +   on 64-bit platforms that would be 2^63).  If it should happen we +   simply don't use this specific key anymore.  */ +#define KEY_USABLE(p) (((uintptr_t) (p)) < ((uintptr_t) ((p) + 2))) + + +/* Handling of read-write lock data.  */ +// XXX For now there is only one flag.  Maybe more in future. +#define RWLOCK_RECURSIVE(rwlock) ((rwlock)->__data.__flags != 0) + + +/* Semaphore variable structure.  */ +struct new_sem +{ +  unsigned int value; +  int private; +  unsigned long int nwaiters; +}; + +struct old_sem +{ +  unsigned int value; +}; + + +/* Compatibility type for old conditional variable interfaces.  */ +typedef struct +{ +  pthread_cond_t *cond; +} pthread_cond_2_0_t; + +#endif	/* internaltypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/jmp-unwind.c b/libpthread/nptl/sysdeps/unix/sysv/linux/jmp-unwind.c new file mode 100644 index 000000000..f2795510a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/jmp-unwind.c @@ -0,0 +1,39 @@ +/* Clean up stack frames unwound by longjmp.  Linux version. +   Copyright (C) 1995, 1997, 2002, 2003, 2007 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#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) +{ +#ifdef SHARED +  if (__libc_pthread_functions_init) +    PTHFCT_CALL (ptr___pthread_cleanup_upto, (env->__jmpbuf, +					      CURRENT_STACK_FRAME)); +#else +  if (__pthread_cleanup_upto != NULL) +    __pthread_cleanup_upto (env->__jmpbuf, CURRENT_STACK_FRAME); +#endif +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/kernel-posix-timers.h b/libpthread/nptl/sysdeps/unix/sysv/linux/kernel-posix-timers.h new file mode 100644 index 000000000..9be630268 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/kernel-posix-timers.h @@ -0,0 +1 @@ +#include <../../../../../../librt/kernel-posix-timers.h> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/libc-lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/libc-lowlevellock.c new file mode 100644 index 000000000..b19282281 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/libc-lowlevellock.c @@ -0,0 +1,21 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +/* No difference to lowlevellock.c, except we lose a couple of functions.  */ +#include "lowlevellock.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/libc_multiple_threads.c b/libpthread/nptl/sysdeps/unix/sysv/linux/libc_multiple_threads.c new file mode 100644 index 000000000..a96f17490 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/libc_multiple_threads.c @@ -0,0 +1,26 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <pthreadP.h> + +#ifndef NOT_IN_libc +# ifndef TLS_MULTIPLE_THREADS_IN_TCB +int __libc_multiple_threads attribute_hidden; +# endif +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c b/libpthread/nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c new file mode 100644 index 000000000..136b44595 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c @@ -0,0 +1,74 @@ +/* Copyright (C) 2002,2003,2005,2006,2007,2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <unistd.h> +#include <list.h> +#include <fork.h> +#include <dl-sysdep.h> +#include <tls.h> +#include <string.h> +#include <pthreadP.h> +#include <bits/libc-lock.h> +#include <sysdep.h> +#include <ldsodefs.h> + + +#ifdef TLS_MULTIPLE_THREADS_IN_TCB +void +#else +extern int __libc_multiple_threads attribute_hidden; + +int * +#endif +__libc_pthread_init ( +     unsigned long int *ptr, +     void (*reclaim) (void), +     const struct pthread_functions *functions) +{ +  /* Remember the pointer to the generation counter in libpthread.  */ +  __fork_generation_pointer = ptr; + +  /* Called by a child after fork.  */ +  __register_atfork (NULL, NULL, reclaim, NULL); + +#ifdef SHARED +  /* We copy the content of the variable pointed to by the FUNCTIONS +     parameter to one in libc.so since this means access to the array +     can be done with one memory access instead of two. +   */ +   memcpy (&__libc_pthread_functions, functions, +           sizeof (__libc_pthread_functions)); +  __libc_pthread_functions_init = 1; +#endif + +#ifndef TLS_MULTIPLE_THREADS_IN_TCB +  return &__libc_multiple_threads; +#endif +} + +#ifdef SHARED +#if 0 +void +libc_freeres_fn (freeres_libptread) +{ +  if (__libc_pthread_functions_init) +    PTHFCT_CALL (ptr_freeres, ()); +} +#endif +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelbarrier.sym b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelbarrier.sym new file mode 100644 index 000000000..cfe22b089 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelbarrier.sym @@ -0,0 +1,12 @@ +#include <stddef.h> +#include <sched.h> +#include <bits/pthreadtypes.h> +#include "internaltypes.h" + +-- + +CURR_EVENT		offsetof (struct pthread_barrier, curr_event) +MUTEX			offsetof (struct pthread_barrier, lock) +LEFT			offsetof (struct pthread_barrier, left) +INIT_COUNT		offsetof (struct pthread_barrier, init_count) +PRIVATE			offsetof (struct pthread_barrier, private) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelcond.sym b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelcond.sym new file mode 100644 index 000000000..18e1adad4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelcond.sym @@ -0,0 +1,16 @@ +#include <stddef.h> +#include <sched.h> +#include <bits/pthreadtypes.h> +#include <internaltypes.h> + +-- + +cond_lock	offsetof (pthread_cond_t, __data.__lock) +cond_futex	offsetof (pthread_cond_t, __data.__futex) +cond_nwaiters	offsetof (pthread_cond_t, __data.__nwaiters) +total_seq	offsetof (pthread_cond_t, __data.__total_seq) +wakeup_seq	offsetof (pthread_cond_t, __data.__wakeup_seq) +woken_seq	offsetof (pthread_cond_t, __data.__woken_seq) +dep_mutex	offsetof (pthread_cond_t, __data.__mutex) +broadcast_seq	offsetof (pthread_cond_t, __data.__broadcast_seq) +nwaiters_shift	COND_NWAITERS_SHIFT diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevellock.c new file mode 100644 index 000000000..e07d78819 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevellock.c @@ -0,0 +1,127 @@ +/* low level locking for pthread library.  Generic futex-using version. +   Copyright (C) 2003, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <sys/time.h> +#include <tls.h> +#include <tcb-offsets.h> + + +void +__lll_lock_wait_private (int *futex) +{ +  if (*futex == 2) +    lll_futex_wait (futex, 2, LLL_PRIVATE); + +  while (atomic_exchange_acq (futex, 2) != 0) +    lll_futex_wait (futex, 2, LLL_PRIVATE); +} + + +/* These functions don't get included in libc.so  */ +#ifdef IS_IN_libpthread +void +__lll_lock_wait (int *futex, int private) +{ +  if (*futex == 2) +    lll_futex_wait (futex, 2, private); + +  while (atomic_exchange_acq (futex, 2) != 0) +    lll_futex_wait (futex, 2, private); +} + + +int +__lll_timedlock_wait (int *futex, const struct timespec *abstime, int private) +{ +  /* Reject invalid timeouts.  */ +  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) +    return EINVAL; + +  /* Try locking.  */ +  while (atomic_exchange_acq (futex, 2) != 0) +    { +      struct timeval tv; + +      /* Get the current time.  */ +      (void) gettimeofday (&tv, NULL); + +      /* Compute relative timeout.  */ +      struct timespec rt; +      rt.tv_sec = abstime->tv_sec - tv.tv_sec; +      rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; +      if (rt.tv_nsec < 0) +	{ +	  rt.tv_nsec += 1000000000; +	  --rt.tv_sec; +	} + +      if (rt.tv_sec < 0) +	return ETIMEDOUT; + +      /* Wait.  */ +      lll_futex_timed_wait (futex, 2, &rt, private); +    } + +  return 0; +} + + +int +__lll_timedwait_tid (int *tidp, const struct timespec *abstime) +{ +  int tid; + +  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) +    return EINVAL; + +  /* Repeat until thread terminated.  */ +  while ((tid = *tidp) != 0) +    { +      struct timeval tv; +      struct timespec rt; + +      /* Get the current time.  */ +      (void) __gettimeofday (&tv, NULL); + +      /* Compute relative timeout.  */ +      rt.tv_sec = abstime->tv_sec - tv.tv_sec; +      rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; +      if (rt.tv_nsec < 0) +	{ +	  rt.tv_nsec += 1000000000; +	  --rt.tv_sec; +	} + +      /* Already timed out?  */ +      if (rt.tv_sec < 0) +	return ETIMEDOUT; + +      /* Wait until thread terminates.  The kernel so far does not use +	 the private futex operations for this.  */ +      if (lll_futex_timed_wait (tidp, tid, &rt, LLL_SHARED) == -ETIMEDOUT) +	return ETIMEDOUT; +    } + +  return 0; +} +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelrobustlock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelrobustlock.c new file mode 100644 index 000000000..3830f94da --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelrobustlock.c @@ -0,0 +1,114 @@ +/* Copyright (C) 2006, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Jakub Jelinek <jakub@redhat.com>, 2006. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <sys/time.h> +#include <pthreadP.h> + + +int +__lll_robust_lock_wait (int *futex, int private) +{ +  int oldval = *futex; +  int tid = THREAD_GETMEM (THREAD_SELF, tid); + +  /* If the futex changed meanwhile try locking again.  */ +  if (oldval == 0) +    goto try; + +  do +    { +      if (__builtin_expect (oldval & FUTEX_OWNER_DIED, 0)) +	return oldval; + +      int newval = oldval | FUTEX_WAITERS; +      if (oldval != newval +	  && atomic_compare_and_exchange_bool_acq (futex, newval, oldval)) +	continue; + +      lll_futex_wait (futex, newval, private); + +    try: +      ; +    } +  while ((oldval = atomic_compare_and_exchange_val_acq (futex, +							tid | FUTEX_WAITERS, +							0)) != 0); +  return 0; +} + + +int +__lll_robust_timedlock_wait (int *futex, const struct timespec *abstime, +			     int private) +{ +  /* Reject invalid timeouts.  */ +  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) +    return EINVAL; + +  int tid = THREAD_GETMEM (THREAD_SELF, tid); +  int oldval = *futex; + +  /* If the futex changed meanwhile try locking again.  */ +  if (oldval == 0) +    goto try; + +  do +    { +      struct timeval tv; +      struct timespec rt; + +      /* Get the current time.  */ +      (void) __gettimeofday (&tv, NULL); + +      /* Compute relative timeout.  */ +      rt.tv_sec = abstime->tv_sec - tv.tv_sec; +      rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; +      if (rt.tv_nsec < 0) +	{ +	  rt.tv_nsec += 1000000000; +	  --rt.tv_sec; +	} + +      /* Already timed out?  */ +      if (rt.tv_sec < 0) +	return ETIMEDOUT; + +      /* Wait.  */ +      if (__builtin_expect (oldval & FUTEX_OWNER_DIED, 0)) +	return oldval; + +      int newval = oldval | FUTEX_WAITERS; +      if (oldval != newval +	  && atomic_compare_and_exchange_bool_acq (futex, newval, oldval)) +	continue; + +      lll_futex_timed_wait (futex, newval, &rt, private); + +    try: +      ; +    } +  while ((oldval = atomic_compare_and_exchange_val_acq (futex, +							tid | FUTEX_WAITERS, +							0)) != 0); + +  return 0; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelrobustlock.sym b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelrobustlock.sym new file mode 100644 index 000000000..2f1e9da52 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelrobustlock.sym @@ -0,0 +1,6 @@ +#include <stddef.h> +#include <pthreadP.h> + +-- + +TID		offsetof (struct pthread, tid) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelrwlock.sym b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelrwlock.sym new file mode 100644 index 000000000..f50b25bfb --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelrwlock.sym @@ -0,0 +1,16 @@ +#include <stddef.h> +#include <stdio.h> +#include <bits/pthreadtypes.h> +#include <bits/wordsize.h> + +-- + +MUTEX		offsetof (pthread_rwlock_t, __data.__lock) +NR_READERS	offsetof (pthread_rwlock_t, __data.__nr_readers) +READERS_WAKEUP	offsetof (pthread_rwlock_t, __data.__readers_wakeup) +WRITERS_WAKEUP	offsetof (pthread_rwlock_t, __data.__writer_wakeup) +READERS_QUEUED	offsetof (pthread_rwlock_t, __data.__nr_readers_queued) +WRITERS_QUEUED	offsetof (pthread_rwlock_t, __data.__nr_writers_queued) +FLAGS		offsetof (pthread_rwlock_t, __data.__flags) +WRITER		offsetof (pthread_rwlock_t, __data.__writer) +PSHARED		offsetof (pthread_rwlock_t, __data.__shared) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/lseek.S b/libpthread/nptl/sysdeps/unix/sysv/linux/lseek.S new file mode 100644 index 000000000..70a920ba1 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/lseek.S @@ -0,0 +1,7 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_lseek, lseek, 3) +ret +PSEUDO_END (__libc_lseek) +libc_hidden_def (__libc_lseek) +weak_alias (__libc_lseek, lseek) +libc_hidden_weak (lseek) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile new file mode 100644 index 000000000..43a6fad84 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../../../../ +top_builddir=../../../../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.arch +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile.arch new file mode 100644 index 000000000..8e7917bb0 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile.arch @@ -0,0 +1,50 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_SSRC = pt-vfork.S +libpthread_CSRC = pthread_once.c pt-__syscall_rt_sigaction.c + +libc_a_CSRC = fork.c + +CFLAGS-OMIT-fork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y) +CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__ +endif +CFLAGS-pthread_once.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-pt-__syscall_rt_sigaction.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +CFLAGS += $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/mips +LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/mips + +LINUX_ARCH_OBJ:=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libpthread_SSRC)) +LINUX_ARCH_OBJ+=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(LINUX_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(LINUX_ARCH_OBJ) +endif +libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y+=$(LINUX_ARCH_OBJS) + +LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC)) + +libc-static-y+=$(LIBC_LINUX_ARCH_OBJ) +libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS) + +libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ) + +objclean-y+=pthread_linux_arch_objclean + +pthread_linux_arch_objclean: +	$(RM) $(LINUX_ARCH_OUT)/*.{o,os,oS} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h new file mode 100644 index 000000000..166a6c6ae --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h @@ -0,0 +1,229 @@ +/* Machine-specific pthread type layouts.  MIPS version. +   Copyright (C) 2005, 2006 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H	1 + +#include <endian.h> + +#if _MIPS_SIM == _ABI64 +# define __SIZEOF_PTHREAD_ATTR_T 56 +# define __SIZEOF_PTHREAD_MUTEX_T 40 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 56 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 32 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#else +# define __SIZEOF_PTHREAD_ATTR_T 36 +# define __SIZEOF_PTHREAD_MUTEX_T 24 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 32 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 20 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#endif + + +/* Thread identifiers.  The structure of the attribute type is +   deliberately not exposed.  */ +typedef unsigned long int pthread_t; + + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_ATTR_T]; +  long int __align; +} pthread_attr_t; + + +#if _MIPS_SIM == _ABI64 +typedef struct __pthread_internal_list +{ +  struct __pthread_internal_list *__prev; +  struct __pthread_internal_list *__next; +} __pthread_list_t; +#else +typedef struct __pthread_internal_slist +{ +  struct __pthread_internal_slist *__next; +} __pthread_slist_t; +#endif + + +/* Data structures for mutex handling.  The structure of the attribute +   type is deliberately not exposed.  */ +typedef union +{ +  struct __pthread_mutex_s +  { +    int __lock; +    unsigned int __count; +    int __owner; +#if _MIPS_SIM == _ABI64 +    unsigned int __nusers; +#endif +    /* KIND must stay at this position in the structure to maintain +       binary compatibility.  */ +    int __kind; +#if _MIPS_SIM == _ABI64 +    int __spins; +    __pthread_list_t __list; +# define __PTHREAD_MUTEX_HAVE_PREV	1 +#else +    unsigned int __nusers; +    __extension__ union +    { +      int __spins; +      __pthread_slist_t __list; +    }; +#endif +  } __data; +  char __size[__SIZEOF_PTHREAD_MUTEX_T]; +  long int __align; +} pthread_mutex_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; +  int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling.  The structure of +   the attribute type is deliberately not exposed.  */ +typedef union +{ +  struct +  { +    int __lock; +    unsigned int __futex; +    __extension__ unsigned long long int __total_seq; +    __extension__ unsigned long long int __wakeup_seq; +    __extension__ unsigned long long int __woken_seq; +    void *__mutex; +    unsigned int __nwaiters; +    unsigned int __broadcast_seq; +  } __data; +  char __size[__SIZEOF_PTHREAD_COND_T]; +  __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_CONDATTR_T]; +  int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling.  The +   structure of the attribute type is deliberately not exposed.  */ +typedef union +{ +# if _MIPS_SIM == _ABI64 +  struct +  { +    int __lock; +    unsigned int __nr_readers; +    unsigned int __readers_wakeup; +    unsigned int __writer_wakeup; +    unsigned int __nr_readers_queued; +    unsigned int __nr_writers_queued; +    int __writer; +    int __shared; +    unsigned long int __pad1; +    unsigned long int __pad2; +    /* FLAGS must stay at this position in the structure to maintain +       binary compatibility.  */ +    unsigned int __flags; +  } __data; +# else +  struct +  { +    int __lock; +    unsigned int __nr_readers; +    unsigned int __readers_wakeup; +    unsigned int __writer_wakeup; +    unsigned int __nr_readers_queued; +    unsigned int __nr_writers_queued; +#if __BYTE_ORDER == __BIG_ENDIAN +    unsigned char __pad1; +    unsigned char __pad2; +    unsigned char __shared; +    /* FLAGS must stay at this position in the structure to maintain +       binary compatibility.  */ +    unsigned char __flags; +#else +    /* FLAGS must stay at this position in the structure to maintain +       binary compatibility.  */ +    unsigned char __flags; +    unsigned char __shared; +    unsigned char __pad1; +    unsigned char __pad2; +#endif +    int __writer; +  } __data; +# endif +  char __size[__SIZEOF_PTHREAD_RWLOCK_T]; +  long int __align; +} pthread_rwlock_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; +  long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type.  */ +typedef volatile int pthread_spinlock_t; + + +/* POSIX barriers data type.  The structure of the type is +   deliberately not exposed.  */ +typedef union +{ +  char __size[__SIZEOF_PTHREAD_BARRIER_T]; +  long int __align; +} pthread_barrier_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; +  int __align; +} pthread_barrierattr_t; +#endif + + +#endif	/* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h new file mode 100644 index 000000000..af43a6048 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h @@ -0,0 +1,37 @@ +/* Copyright (C) 2002, 2005, 2007 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + +#if _MIPS_SIM == _ABI64 +# define __SIZEOF_SEM_T	32 +#else +# define __SIZEOF_SEM_T	16 +#endif + +/* Value returned if `sem_open' failed.  */ +#define SEM_FAILED      ((sem_t *) 0) + + +typedef union +{ +  char __size[__SIZEOF_SEM_T]; +  long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/createthread.c new file mode 100644 index 000000000..d8a7c5539 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/createthread.c @@ -0,0 +1,24 @@ +/* Copyright (C) 2005 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +/* Value passed to 'clone' for initialization of the thread register.  */ +#define TLS_VALUE ((void *) (pd) \ +		   + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE) + +/* Get the real implementation.	 */ +#include <sysdeps/pthread/createthread.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/fork.c new file mode 100644 index 000000000..06b7e1c69 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/fork.c @@ -0,0 +1 @@ +#include "../i386/fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h new file mode 100644 index 000000000..01bcf4120 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h @@ -0,0 +1,295 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, +   2009 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H	1 + +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> +#include <atomic.h> +#include <sysdep.h> +#include <bits/kernel-features.h> + +#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_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(futexp, val, private) \ +  lll_futex_timed_wait(futexp, val, NULL, private) + +#define lll_futex_timed_wait(futexp, val, timespec, private) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4, (long) (futexp),		      \ +			      __lll_private_flag (FUTEX_WAIT, private),	      \ +			      (val), (timespec));			      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;		      \ +  }) + +#define lll_futex_wake(futexp, nr, private) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4, (long) (futexp),		      \ +			      __lll_private_flag (FUTEX_WAKE, private),	      \ +			      (nr), 0);	      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;		      \ +  }) + +#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, (long) (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);				      \ +  }) + +static inline int __attribute__((always_inline)) +__lll_trylock(int *futex) +{ +  return atomic_compare_and_exchange_val_acq (futex, 1, 0) != 0; +} +#define lll_trylock(lock)	__lll_trylock (&(lock)) + + +static inline int __attribute__((always_inline)) +__lll_cond_trylock(int *futex) +{ +  return atomic_compare_and_exchange_val_acq (futex, 2, 0) != 0; +} +#define lll_cond_trylock(lock)	__lll_cond_trylock (&(lock)) + + +static inline int __attribute__((always_inline)) +__lll_robust_trylock(int *futex, int id) +{ +  return atomic_compare_and_exchange_val_acq (futex, id, 0) != 0; +} +#define lll_robust_trylock(lock, id) \ +  __lll_robust_trylock (&(lock), 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; + +#define __lll_lock(futex, private)					      \ +  ((void) ({								      \ +    int *__futex = (futex);						      \ +    if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex,      \ +								1, 0), 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) + + +#define __lll_robust_lock(futex, id, private)				      \ +  ({									      \ +    int *__futex = (futex);						      \ +    int __val = 0;							      \ +									      \ +    if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \ +								0), 0))	      \ +      __val = __lll_robust_lock_wait (__futex, private);		      \ +    __val;								      \ +  }) +#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 (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 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 (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0) +    result = __lll_timedlock_wait (futex, abstime, private); +  return result; +} +#define lll_timedlock(futex, abstime, private) \ +  __lll_timedlock (&(futex), abstime, private) + + +static inline int __attribute__ ((always_inline)) +__lll_robust_timedlock (int *futex, const struct timespec *abstime, +			int id, int private) +{ +  int result = 0; +  if (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 *__futex = (futex);						      \ +    int __val = atomic_exchange_rel (__futex, 0);			      \ +									      \ +    if (__builtin_expect (__val > 1, 0))				      \ +      lll_futex_wake (__futex, 1, private);				      \ +  })) +#define lll_unlock(futex, private) __lll_unlock(&(futex), private) + + +#define __lll_robust_unlock(futex, private)				      \ +  ((void) ({								      \ +    int *__futex = (futex);						      \ +    int __val = atomic_exchange_rel (__futex, 0);			      \ +									      \ +    if (__builtin_expect (__val & FUTEX_WAITERS, 0))			      \ +      lll_futex_wake (__futex, 1, private);				      \ +  })) +#define lll_robust_unlock(futex, private) \ +  __lll_robust_unlock(&(futex), private) + + +#define lll_islocked(futex) \ +  (futex != 0) + + +/* Our internal lock implementation is identical to the binary-compatible +   mutex implementation. */ + +/* Initializers for lock.  */ +#define LLL_LOCK_INITIALIZER		(0) +#define LLL_LOCK_INITIALIZER_LOCKED	(1) + +/* The states of a lock are: +    0  -  untaken +    1  -  taken by one user +   >1  -  taken by more users */ + +/* The kernel notifies a process which uses CLONE_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(tid) \ +  do {							\ +    __typeof (tid) __tid;				\ +    while ((__tid = (tid)) != 0)			\ +      lll_futex_wait (&(tid), __tid, LLL_SHARED);	\ +  } while (0) + +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;						\ +  }) + +#endif	/* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-__syscall_rt_sigaction.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-__syscall_rt_sigaction.c new file mode 100644 index 000000000..50137c84a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-__syscall_rt_sigaction.c @@ -0,0 +1 @@ +#include <../../../../../../../libc/sysdeps/linux/common/__syscall_rt_sigaction.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-clone.S new file mode 100644 index 000000000..add405523 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-clone.S @@ -0,0 +1,2 @@ +#define RESET_PID +#include <../../../../../../../libc/sysdeps/linux/mips/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S new file mode 100644 index 000000000..c02ffca93 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S @@ -0,0 +1,38 @@ +/* Copyright (C) 2005 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <features.h> +#include <tls.h> + +/* Save the PID value.  */ +#define SAVE_PID \ +	READ_THREAD_POINTER(v1);	/* Get the thread pointer.  */	\ +	lw	a2, PID_OFFSET(v1);	/* Load the saved PID.  */	\ +	subu	a2, $0, a2;		/* Negate it.  */		\ +	sw	a2, PID_OFFSET(v1);	/* Store the temporary PID.  */ + +/* Restore the old PID value in the parent.  */ +#define RESTORE_PID \ +	beqz	v0, 1f;			/* If we are the parent... */	\ +	READ_THREAD_POINTER(v1);	/* Get the thread pointer.  */	\ +	lw	a2, PID_OFFSET(v1);	/* Load the saved PID.  */	\ +	subu	a2, $0, a2;		/* Re-negate it.  */		\ +	sw	a2, PID_OFFSET(v1);	/* Restore the PID.  */		\ +1: + +#include <../../../../../../../libc/sysdeps/linux/mips/vfork.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c new file mode 100644 index 000000000..cc4658b32 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c @@ -0,0 +1,95 @@ +/* Copyright (C) 2003, 2004, 2005 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#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 +attribute_protected +__pthread_once (once_control, init_routine) +     pthread_once_t *once_control; +     void (*init_routine) (void); +{ +  while (1) +    { +      int oldval, val, newval; + +      val = *once_control; +      do +	{ +	  /* Check if the initialized has already been done.  */ +	  if ((val & 2) != 0) +	    return 0; + +	  oldval = val; +	  newval = (oldval & 3) | __fork_generation | 1; +	  val = atomic_compare_and_exchange_val_acq (once_control, newval, +						     oldval); +	} +      while (__builtin_expect (val != oldval, 0)); + +      /* 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.  */ +      atomic_increment (once_control); + +      /* Wake up all other threads.  */ +      lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE); +      break; +    } + +  return 0; +} +weak_alias (__pthread_once, pthread_once) +strong_alias (__pthread_once, __pthread_once_internal) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h new file mode 100644 index 000000000..1cf625f4e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h @@ -0,0 +1,188 @@ +/* Copyright (C) 2003, 2004, 2005 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# ifdef __PIC__ +#  define PSEUDO_CPLOAD .cpload t9; +#  define PSEUDO_ERRJMP la t9, __syscall_error; jr t9; +#  define PSEUDO_SAVEGP sw gp, 32(sp); cfi_rel_offset (gp, 32); +#  define PSEUDO_LOADGP lw gp, 32(sp); +# else +#  define PSEUDO_CPLOAD +#  define PSEUDO_ERRJMP j __syscall_error; +#  define PSEUDO_SAVEGP +#  define PSEUDO_LOADGP +# endif + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args)				      \ +      .align 2;								      \ +  L(pseudo_start):							      \ +      cfi_startproc;							      \ +  99: PSEUDO_ERRJMP							      \ +  .type __##syscall_name##_nocancel, @function;				      \ +  .globl __##syscall_name##_nocancel;					      \ +  __##syscall_name##_nocancel:						      \ +    .set noreorder;							      \ +    PSEUDO_CPLOAD							      \ +    li v0, SYS_ify(syscall_name);					      \ +    syscall;								      \ +    .set reorder;							      \ +    bne a3, zero, 99b;					       		      \ +    ret;								      \ +  .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;	      \ +  ENTRY (name)								      \ +    .set noreorder;							      \ +    PSEUDO_CPLOAD							      \ +    .set reorder;							      \ +    SINGLE_THREAD_P(v1);						      \ +    bne zero, v1, L(pseudo_cancel);					      \ +    .set noreorder;							      \ +    li v0, SYS_ify(syscall_name);					      \ +    syscall;								      \ +    .set reorder;							      \ +    bne a3, zero, 99b;					       		      \ +    ret;								      \ +  L(pseudo_cancel):							      \ +    SAVESTK_##args;						              \ +    sw ra, 28(sp);							      \ +    cfi_rel_offset (ra, 28);						      \ +    PSEUDO_SAVEGP							      \ +    PUSHARGS_##args;			/* save syscall args */	      	      \ +    CENABLE;								      \ +    PSEUDO_LOADGP							      \ +    sw v0, 44(sp);			/* save mask */			      \ +    POPARGS_##args;			/* restore syscall args */	      \ +    .set noreorder;							      \ +    li v0, SYS_ify (syscall_name);				      	      \ +    syscall;								      \ +    .set reorder;							      \ +    sw v0, 36(sp);			/* save syscall result */             \ +    sw a3, 40(sp);			/* save syscall error flag */	      \ +    lw a0, 44(sp);			/* pass mask as arg1 */		      \ +    CDISABLE;								      \ +    PSEUDO_LOADGP							      \ +    lw v0, 36(sp);			/* restore syscall result */          \ +    lw a3, 40(sp);			/* restore syscall error flag */      \ +    lw ra, 28(sp);			/* restore return address */	      \ +    .set noreorder;							      \ +    bne a3, zero, 99b;							      \ +     RESTORESTK;						              \ +  L(pseudo_end):							      \ +    .set reorder; + +# undef PSEUDO_END +# define PSEUDO_END(sym) cfi_endproc; .end sym; .size sym,.-sym + +# define PUSHARGS_0	/* nothing to do */ +# define PUSHARGS_1	PUSHARGS_0 sw a0, 0(sp); cfi_rel_offset (a0, 0); +# define PUSHARGS_2	PUSHARGS_1 sw a1, 4(sp); cfi_rel_offset (a1, 4); +# define PUSHARGS_3	PUSHARGS_2 sw a2, 8(sp); cfi_rel_offset (a2, 8); +# define PUSHARGS_4	PUSHARGS_3 sw a3, 12(sp); cfi_rel_offset (a3, 12); +# define PUSHARGS_5	PUSHARGS_4 /* handled by SAVESTK_## */ +# define PUSHARGS_6	PUSHARGS_5 +# define PUSHARGS_7	PUSHARGS_6 + +# define POPARGS_0	/* nothing to do */ +# define POPARGS_1	POPARGS_0 lw a0, 0(sp); +# define POPARGS_2	POPARGS_1 lw a1, 4(sp); +# define POPARGS_3	POPARGS_2 lw a2, 8(sp); +# define POPARGS_4	POPARGS_3 lw a3, 12(sp); +# define POPARGS_5	POPARGS_4 /* args already in new stackframe */ +# define POPARGS_6	POPARGS_5 +# define POPARGS_7	POPARGS_6 + + +# define STKSPACE	48 +# define SAVESTK_0 	subu sp, STKSPACE; cfi_adjust_cfa_offset(STKSPACE) +# define SAVESTK_1      SAVESTK_0 +# define SAVESTK_2      SAVESTK_1 +# define SAVESTK_3      SAVESTK_2 +# define SAVESTK_4      SAVESTK_3 +# define SAVESTK_5      lw t0, 16(sp);		\ +			SAVESTK_0;		\ +			sw t0, 16(sp) + +# define SAVESTK_6      lw t0, 16(sp);		\ +			lw t1, 20(sp);		\ +			SAVESTK_0;		\ +			sw t0, 16(sp);		\ +			sw t1, 20(sp) + +# define SAVESTK_7      lw t0, 16(sp);		\ +			lw t1, 20(sp);		\ +			lw t2, 24(sp);		\ +			SAVESTK_0;		\ +			sw t0, 16(sp);		\ +			sw t1, 20(sp);		\ +			sw t2, 24(sp) + +# define RESTORESTK 	addu sp, STKSPACE; cfi_adjust_cfa_offset(-STKSPACE) + + +# ifdef __PIC__ +/* We use jalr rather than jal.  This means that the assembler will not +   automatically restore $gp (in case libc has multiple GOTs) so we must +   do it manually - which we have to do anyway since we don't use .cprestore. +   It also shuts up the assembler warning about not using .cprestore.  */ +#  define PSEUDO_JMP(sym) la t9, sym; jalr t9; +# else +#  define PSEUDO_JMP(sym) jal sym; +# endif + +# ifdef IS_IN_libpthread +#  define CENABLE	PSEUDO_JMP (__pthread_enable_asynccancel) +#  define CDISABLE	PSEUDO_JMP (__pthread_disable_asynccancel) +# elif defined IS_IN_librt +#  define CENABLE	PSEUDO_JMP (__librt_enable_asynccancel) +#  define CDISABLE	PSEUDO_JMP (__librt_disable_asynccancel) +# else +#  define CENABLE	PSEUDO_JMP (__libc_enable_asynccancel) +#  define CDISABLE	PSEUDO_JMP (__libc_disable_asynccancel) +# endif + +# ifndef __ASSEMBLER__ +#  define SINGLE_THREAD_P						\ +	__builtin_expect (THREAD_GETMEM (THREAD_SELF,			\ +					 header.multiple_threads)	\ +			  == 0, 1) +# else +#  define SINGLE_THREAD_P(reg)						\ +	READ_THREAD_POINTER(reg);					\ +	lw reg, 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/libpthread/nptl/sysdeps/unix/sysv/linux/mq_notify.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mq_notify.c new file mode 100644 index 000000000..188040ee8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mq_notify.c @@ -0,0 +1,286 @@ +/* Copyright (C) 2004, 2005, 2008 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contribute by Ulrich Drepper <drepper@redhat.com>, 2004. + +   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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <pthread.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <sysdep.h> +#include <unistd.h> +#include <sys/socket.h> +#include <not-cancel.h> +#include <bits/kernel-features.h> + + +#ifdef __NR_mq_notify + +/* Defined in the kernel headers: */ +#define NOTIFY_COOKIE_LEN	32	/* Length of the cookie used.  */ +#define NOTIFY_WOKENUP		1	/* Code for notifcation.  */ +#define NOTIFY_REMOVED		2	/* Code for closed message queue +					   of de-notifcation.  */ + + +/* Data structure for the queued notification requests.  */ +union notify_data +{ +  struct +  { +    void (*fct) (union sigval);	/* The function to run.  */ +    union sigval param;		/* The parameter to pass.  */ +    pthread_attr_t *attr;	/* Attributes to create the thread with.  */ +    /* NB: on 64-bit machines the struct as a size of 24 bytes.  Which means +       byte 31 can still be used for returning the status.  */ +  }; +  char raw[NOTIFY_COOKIE_LEN]; +}; + + +/* Keep track of the initialization.  */ +static pthread_once_t once = PTHREAD_ONCE_INIT; + + +/* The netlink socket.  */ +static int netlink_socket = -1; + + +/* Barrier used to make sure data passed to the new thread is not +   resused by the parent.  */ +static pthread_barrier_t notify_barrier; + + +/* Modify the signal mask.  We move this into a separate function so +   that the stack space needed for sigset_t is not deducted from what +   the thread can use.  */ +static int +__attribute__ ((noinline)) +change_sigmask (int how, sigset_t *oss) +{ +  sigset_t ss; +  sigfillset (&ss); +  return pthread_sigmask (how, &ss, oss); +} + + +/* The function used for the notification.  */ +static void * +notification_function (void *arg) +{ +  /* Copy the function and parameter so that the parent thread can go +     on with its life.  */ +  volatile union notify_data *data = (volatile union notify_data *) arg; +  void (*fct) (union sigval) = data->fct; +  union sigval param = data->param; + +  /* Let the parent go.  */ +  (void) pthread_barrier_wait (¬ify_barrier); + +  /* Make the thread detached.  */ +  (void) pthread_detach (pthread_self ()); + +  /* The parent thread has all signals blocked.  This is probably a +     bit surprising for this thread.  So we unblock all of them.  */ +  (void) change_sigmask (SIG_UNBLOCK, NULL); + +  /* Now run the user code.  */ +  fct (param); + +  /* And we are done.  */ +  return NULL; +} + + +/* Helper thread.  */ +static void * +helper_thread (void *arg) +{ +  while (1) +    { +      union notify_data data; + +      ssize_t n = recv (netlink_socket, &data, sizeof (data), +			MSG_NOSIGNAL | MSG_WAITALL); +      if (n < NOTIFY_COOKIE_LEN) +	continue; + +      if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_WOKENUP) +	{ +	  /* Just create the thread as instructed.  There is no way to +	     report a problem with creating a thread.  */ +	  pthread_t th; +	  if (__builtin_expect (pthread_create (&th, data.attr, +						notification_function, &data) +				== 0, 0)) +	    /* Since we passed a pointer to DATA to the new thread we have +	       to wait until it is done with it.  */ +	    (void) pthread_barrier_wait (¬ify_barrier); +	} +      else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED) +	/* The only state we keep is the copy of the thread attributes.  */ +	free (data.attr); +    } +  return NULL; +} + + +static void +reset_once (void) +{ +  once = PTHREAD_ONCE_INIT; +} + + +static void +init_mq_netlink (void) +{ +  /* This code might be called a second time after fork().  The file +     descriptor is inherited from the parent.  */ +  if (netlink_socket == -1) +    { +      /* Just a normal netlink socket, not bound.  */ +	  netlink_socket = socket (AF_NETLINK, SOCK_RAW, 0); +      /* No need to do more if we have no socket.  */ +      if (netlink_socket == -1) +	return; + +      /* Make sure the descriptor is closed on exec.  */ +      if (fcntl (netlink_socket, F_SETFD, FD_CLOEXEC) != 0) +	goto errout; +    } + +  int err = 1; + +  /* Initialize the barrier.  */ +  if (__builtin_expect (pthread_barrier_init (¬ify_barrier, NULL, 2) == 0, +			0)) +    { +      /* Create the helper thread.  */ +      pthread_attr_t attr; +      (void) pthread_attr_init (&attr); +      (void) pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); +      /* We do not need much stack space, the bare minimum will be enough.  */ +      (void) pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN); + +      /* Temporarily block all signals so that the newly created +	 thread inherits the mask.  */ +      sigset_t oss; +      int have_no_oss = change_sigmask (SIG_BLOCK, &oss); + +      pthread_t th; +      err = pthread_create (&th, &attr, helper_thread, NULL); + +      /* Reset the signal mask.  */ +      if (!have_no_oss) +	pthread_sigmask (SIG_SETMASK, &oss, NULL); + +      (void) pthread_attr_destroy (&attr); + +      if (err == 0) +	{ +	  static int added_atfork; + +	  if (added_atfork == 0 +	      && pthread_atfork (NULL, NULL, reset_once) != 0) +	    { +	      /* The child thread will call recv() which is a +		 cancellation point.  */ +	      (void) pthread_cancel (th); +	      err = 1; +	    } +	  else +	    added_atfork = 1; +	} +    } + +  if (err != 0) +    { +    errout: +      close_not_cancel_no_status (netlink_socket); +      netlink_socket = -1; +    } +} + + +/* Register notification upon message arrival to an empty message queue +   MQDES.  */ +int +mq_notify (mqd_t mqdes, const struct sigevent *notification) +{ +  /* Make sure the type is correctly defined.  */ +  assert (sizeof (union notify_data) == NOTIFY_COOKIE_LEN); + +  /* Special treatment needed for SIGEV_THREAD.  */ +  if (notification == NULL || notification->sigev_notify != SIGEV_THREAD) +    return INLINE_SYSCALL (mq_notify, 2, mqdes, notification); + +  /* The kernel cannot directly start threads.  This will have to be +     done at userlevel.  Since we cannot start threads from signal +     handlers we have to create a dedicated thread which waits for +     notifications for arriving messages and creates threads in +     response.  */ + +  /* Initialize only once.  */ +  pthread_once (&once, init_mq_netlink); + +  /* If we cannot create the netlink socket we cannot provide +     SIGEV_THREAD support.  */ +  if (__builtin_expect (netlink_socket == -1, 0)) +    { +      __set_errno (ENOSYS); +      return -1; +    } + +  /* Create the cookie.  It will hold almost all the state.  */ +  union notify_data data; +  memset (&data, '\0', sizeof (data)); +  data.fct = notification->sigev_notify_function; +  data.param = notification->sigev_value; + +  if (notification->sigev_notify_attributes != NULL) +    { +      /* The thread attribute has to be allocated separately.  */ +      data.attr = (pthread_attr_t *) malloc (sizeof (pthread_attr_t)); +      if (data.attr == NULL) +	return -1; + +      memcpy (data.attr, notification->sigev_notify_attributes, +	      sizeof (pthread_attr_t)); +    } + +  /* Construct the new request.  */ +  struct sigevent se; +  se.sigev_notify = SIGEV_THREAD; +  se.sigev_signo = netlink_socket; +  se.sigev_value.sival_ptr = &data; + +  /* Tell the kernel.  */ +  int retval = INLINE_SYSCALL (mq_notify, 2, mqdes, &se); + +  /* If it failed, free the allocated memory.  */ +  if (__builtin_expect (retval != 0, 0)) +    free (data.attr); + +  return retval; +} + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/msync.S b/libpthread/nptl/sysdeps/unix/sysv/linux/msync.S new file mode 100644 index 000000000..074a0d717 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/msync.S @@ -0,0 +1,7 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_msync, msync, 3) +ret +PSEUDO_END(__libc_msync) +libc_hidden_def (__libc_msync) +weak_alias (__libc_msync, msync) +libc_hidden_weak (msync) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nanosleep.S b/libpthread/nptl/sysdeps/unix/sysv/linux/nanosleep.S new file mode 100644 index 000000000..71efe32f9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nanosleep.S @@ -0,0 +1,9 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_nanosleep, nanosleep, 3) +ret +PSEUDO_END (__libc_nanosleep) +libc_hidden_def (__libc_nanosleep) +weak_alias (__libc_nanosleep, __nanosleep) +libc_hidden_weak (__nanosleep) +weak_alias (__libc_nanosleep, nanosleep) +libc_hidden_weak (nanosleep) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/not-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/not-cancel.h new file mode 100644 index 000000000..80d33be29 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/not-cancel.h @@ -0,0 +1,105 @@ +/* Uncancelable versions of cancelable interfaces.  Linux version. +   Copyright (C) 2003, 2006 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sys/types.h> +#include <sysdep.h> + +/* Uncancelable open.  */ +#define open_not_cancel(name, flags, mode) \ +   INLINE_SYSCALL (open, 3, (const char *) (name), (flags), (mode)) +#define open_not_cancel_2(name, flags) \ +   INLINE_SYSCALL (open, 2, (const char *) (name), (flags)) + +/* Uncancelable openat.  */ +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt +extern int __openat_nocancel (int fd, const char *fname, int oflag, +			      mode_t mode) attribute_hidden; +extern int __openat64_nocancel (int fd, const char *fname, int oflag, +				mode_t mode) attribute_hidden; +#else +# define __openat_nocancel(fd, fname, oflag, mode) \ +  openat (fd, fname, oflag, mode) +# define __openat64_nocancel(fd, fname, oflag, mode) \ +  openat64 (fd, fname, oflag, mode) +#endif + +#define openat_not_cancel(fd, fname, oflag, mode) \ +  __openat_nocancel (fd, fname, oflag, mode) +#define openat_not_cancel_3(fd, fname, oflag) \ +  __openat_nocancel (fd, fname, oflag, 0) +#define openat64_not_cancel(fd, fname, oflag, mode) \ +  __openat64_nocancel (fd, fname, oflag, mode) +#define openat64_not_cancel_3(fd, fname, oflag) \ +  __openat64_nocancel (fd, fname, oflag, 0) + +/* Uncancelable close.  */ +#define close_not_cancel(fd) \ +  INLINE_SYSCALL (close, 1, fd) +#define close_not_cancel_no_status(fd) \ +  (void) ({ INTERNAL_SYSCALL_DECL (err);				      \ +	    INTERNAL_SYSCALL (close, err, 1, (fd)); }) + +/* Uncancelable read.  */ +#define read_not_cancel(fd, buf, n) \ +  INLINE_SYSCALL (read, 3, (fd), (buf), (n)) + +/* Uncancelable write.  */ +#define write_not_cancel(fd, buf, n) \ +  INLINE_SYSCALL (write, 3, (fd), (buf), (n)) + +/* Uncancelable writev.  */ +#define writev_not_cancel_no_status(fd, iov, n) \ +  (void) ({ INTERNAL_SYSCALL_DECL (err);				      \ +	    INTERNAL_SYSCALL (writev, err, 3, (fd), (iov), (n)); }) + +/* Uncancelable fcntl.  */ +#define fcntl_not_cancel(fd, cmd, val) \ +  __fcntl_nocancel (fd, cmd, val) + +/* Uncancelable waitpid.  */ +#ifdef __NR_waitpid +# define waitpid_not_cancel(pid, stat_loc, options) \ +  INLINE_SYSCALL (waitpid, 3, pid, stat_loc, options) +#else +# define waitpid_not_cancel(pid, stat_loc, options) \ +  INLINE_SYSCALL (wait4, 4, pid, stat_loc, options, NULL) +#endif + +/* Uncancelable pause.  */ +#ifdef __NR_pause +# define pause_not_cancel() \ +  INLINE_SYSCALL (pause, 0) +#else +# define pause_not_cancel() \ +  __pause_nocancel () +#endif + +/* Uncancelable nanosleep.  */ +#ifdef __NR_nanosleep +# define nanosleep_not_cancel(requested_time, remaining) \ +  INLINE_SYSCALL (nanosleep, 2, requested_time, remaining) +#else +# define nanosleep_not_cancel(requested_time, remaining) \ +  __nanosleep_nocancel (requested_time, remaining) +#endif + +/* Uncancelable sigsuspend.  */ +#define sigsuspend_not_cancel(set) \ +  __sigsuspend_nocancel (set) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/open.S b/libpthread/nptl/sysdeps/unix/sysv/linux/open.S new file mode 100644 index 000000000..486686a22 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/open.S @@ -0,0 +1,21 @@ +#include <sysdep-cancel.h> + +/* +extern int __open_nocancel (const char *, int, ...) attribute_hidden; +*/ +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +PSEUDO (__libc_open, open, 3) +ret +PSEUDO_END(__libc_open) + +libc_hidden_def (__open_nocancel) +libc_hidden_def (__libc_open) +weak_alias (__libc_open, __open) +libc_hidden_weak (__open) +weak_alias (__libc_open, open) +libc_hidden_weak (open) + + + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pause.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pause.S new file mode 100644 index 000000000..3841018a8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pause.S @@ -0,0 +1,7 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_pause, pause, 0) +ret +PSEUDO_END (__libc_pause) +libc_hidden_def (__libc_pause) +weak_alias (__libc_pause, pause) +libc_hidden_weak (pause) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/Makefile new file mode 100644 index 000000000..e98c9bd86 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/Makefile @@ -0,0 +1,2 @@ +# pull in __syscall_error routine +libpthread-routines += sysdep diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h new file mode 100644 index 000000000..c0b59c336 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h @@ -0,0 +1,221 @@ +/* Machine-specific pthread type layouts.  PowerPC version. +   Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H	1 + +#include <bits/wordsize.h> + +#if __WORDSIZE == 64 +# define __SIZEOF_PTHREAD_ATTR_T 56 +# define __SIZEOF_PTHREAD_MUTEX_T 40 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 56 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 32 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#else +# define __SIZEOF_PTHREAD_ATTR_T 36 +# define __SIZEOF_PTHREAD_MUTEX_T 24 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 32 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 20 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#endif + + +/* Thread identifiers.  The structure of the attribute type is +   deliberately not exposed.  */ +typedef unsigned long int pthread_t; + + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_ATTR_T]; +  long int __align; +} pthread_attr_t; + + +#if __WORDSIZE == 64 +typedef struct __pthread_internal_list +{ +  struct __pthread_internal_list *__prev; +  struct __pthread_internal_list *__next; +} __pthread_list_t; +#else +typedef struct __pthread_internal_slist +{ +  struct __pthread_internal_slist *__next; +} __pthread_slist_t; +#endif + + +/* Data structures for mutex handling.  The structure of the attribute +   type is deliberately not exposed.  */ +typedef union +{ +  struct __pthread_mutex_s +  { +    int __lock; +    unsigned int __count; +    int __owner; +#if __WORDSIZE == 64 +    unsigned int __nusers; +#endif +    /* KIND must stay at this position in the structure to maintain +       binary compatibility.  */ +    int __kind; +#if __WORDSIZE == 64 +    int __spins; +    __pthread_list_t __list; +# define __PTHREAD_MUTEX_HAVE_PREV	1 +#else +    unsigned int __nusers; +    __extension__ union +    { +      int __spins; +      __pthread_slist_t __list; +    }; +#endif +  } __data; +  char __size[__SIZEOF_PTHREAD_MUTEX_T]; +  long int __align; +} pthread_mutex_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; +  int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling.  The structure of +   the attribute type is deliberately not exposed.  */ +typedef union +{ +  struct +  { +    int __lock; +    unsigned int __futex; +    __extension__ unsigned long long int __total_seq; +    __extension__ unsigned long long int __wakeup_seq; +    __extension__ unsigned long long int __woken_seq; +    void *__mutex; +    unsigned int __nwaiters; +    unsigned int __broadcast_seq; +  } __data; +  char __size[__SIZEOF_PTHREAD_COND_T]; +  __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_CONDATTR_T]; +  int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling.  The +   structure of the attribute type is deliberately not exposed.  */ +typedef union +{ +# if __WORDSIZE == 64 +  struct +  { +    int __lock; +    unsigned int __nr_readers; +    unsigned int __readers_wakeup; +    unsigned int __writer_wakeup; +    unsigned int __nr_readers_queued; +    unsigned int __nr_writers_queued; +    int __writer; +    int __shared; +    unsigned long int __pad1; +    unsigned long int __pad2; +    /* FLAGS must stay at this position in the structure to maintain +       binary compatibility.  */ +    unsigned int __flags; +  } __data; +# else +  struct +  { +    int __lock; +    unsigned int __nr_readers; +    unsigned int __readers_wakeup; +    unsigned int __writer_wakeup; +    unsigned int __nr_readers_queued; +    unsigned int __nr_writers_queued; +    unsigned char __pad1; +    unsigned char __pad2; +    unsigned char __shared; +    /* FLAGS must stay at this position in the structure to maintain +       binary compatibility.  */ +    unsigned char __flags; +    int __writer; +  } __data; +# endif +  char __size[__SIZEOF_PTHREAD_RWLOCK_T]; +  long int __align; +} pthread_rwlock_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; +  long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type.  */ +typedef volatile int pthread_spinlock_t; + + +/* POSIX barriers data type.  The structure of the type is +   deliberately not exposed.  */ +typedef union +{ +  char __size[__SIZEOF_PTHREAD_BARRIER_T]; +  long int __align; +} pthread_barrier_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; +  int __align; +} pthread_barrierattr_t; +#endif + + +#endif	/* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/semaphore.h new file mode 100644 index 000000000..c7f121ba5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/semaphore.h @@ -0,0 +1,41 @@ +/* Machine-specific POSIX semaphore type layouts.  PowerPC version. +   Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + +#include <bits/wordsize.h> + +#if __WORDSIZE == 64 +# define __SIZEOF_SEM_T	32 +#else +# define __SIZEOF_SEM_T	16 +#endif + +/* Value returned if `sem_open' failed.  */ +#define SEM_FAILED      ((sem_t *) 0) + + +typedef union +{ +  char __size[__SIZEOF_SEM_T]; +  long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/createthread.c new file mode 100644 index 000000000..e811ad74e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/createthread.c @@ -0,0 +1,25 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Paul Mackerras <paulus@au.ibm.com>. + +   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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +/* Value passed to 'clone' for initialization of the thread register.  */ +#define TLS_VALUE ((void *) (pd) \ +		   + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE) + +/* Get the real implementation.	 */ +#include <nptl/sysdeps/pthread/createthread.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/fork.c new file mode 100644 index 000000000..06b7e1c69 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/fork.c @@ -0,0 +1 @@ +#include "../i386/fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h new file mode 100644 index 000000000..66c02cbbd --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h @@ -0,0 +1,314 @@ +/* Copyright (C) 2003, 2004, 2006-2008, 2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#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> + +#ifndef __NR_futex +# define __NR_futex		221 +#endif +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 +#define FUTEX_REQUEUE		3 +#define FUTEX_CMP_REQUEUE	4 +#define FUTEX_WAKE_OP		5 +#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE	((4 << 24) | 1) +#define FUTEX_LOCK_PI		6 +#define FUTEX_UNLOCK_PI		7 +#define FUTEX_TRYLOCK_PI	8 +#define FUTEX_WAIT_BITSET	9 +#define FUTEX_WAKE_BITSET	10 +#define FUTEX_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(futexp, val, private) \ +  lll_futex_timed_wait (futexp, val, NULL, private) + +#define lll_futex_timed_wait(futexp, val, timespec, private) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +									      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),		      \ +			      __lll_private_flag (FUTEX_WAIT, private),	      \ +			      (val), (timespec));			      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;		      \ +  }) + +#define lll_futex_wake(futexp, nr, private) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +									      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),		      \ +			      __lll_private_flag (FUTEX_WAKE, private),	      \ +			      (nr), 0);					      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;		      \ +  }) + +#define lll_robust_dead(futexv, private) \ +  do									      \ +    {									      \ +      INTERNAL_SYSCALL_DECL (__err);					      \ +      int *__futexp = &(futexv);					      \ +									      \ +      atomic_or (__futexp, FUTEX_OWNER_DIED);				      \ +      INTERNAL_SYSCALL (futex, __err, 4, __futexp,			      \ +			__lll_private_flag (FUTEX_WAKE, private), 1, 0);      \ +    }									      \ +  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);				      \ +  }) + + +#ifdef UP +# define __lll_acq_instr	"" +# define __lll_rel_instr	"" +#else +# define __lll_acq_instr	"isync" +# ifdef _ARCH_PWR4 +/* + * Newer powerpc64 processors support the new "light weight" sync (lwsync) + * So if the build is using -mcpu=[power4,power5,power5+,970] we can + * safely use lwsync. + */ +#  define __lll_rel_instr	"lwsync" +# else +/* + * Older powerpc32 processors don't support the new "light weight" + * sync (lwsync).  So the only safe option is to use normal sync + * for all powerpc32 applications. + */ +#  define __lll_rel_instr	"sync" +# endif +#endif + +/* Set *futex to ID if it is 0, atomically.  Returns the old value */ +#define __lll_robust_trylock(futex, id) \ +  ({ int __val;								      \ +     __asm __volatile ("1:	lwarx	%0,0,%2" MUTEX_HINT_ACQ "\n"	      \ +		       "	cmpwi	0,%0,0\n"			      \ +		       "	bne	2f\n"				      \ +		       "	stwcx.	%3,0,%2\n"			      \ +		       "	bne-	1b\n"				      \ +		       "2:	" __lll_acq_instr			      \ +		       : "=&r" (__val), "=m" (*futex)			      \ +		       : "r" (futex), "r" (id), "m" (*futex)		      \ +		       : "cr0", "memory");				      \ +     __val;								      \ +  }) + +#define lll_robust_trylock(lock, id) __lll_robust_trylock (&(lock), id) + +/* Set *futex to 1 if it is 0, atomically.  Returns the old value */ +#define __lll_trylock(futex) __lll_robust_trylock (futex, 1) + +#define lll_trylock(lock)	__lll_trylock (&(lock)) + +/* Set *futex to 2 if it is 0, atomically.  Returns the old value */ +#define __lll_cond_trylock(futex) __lll_robust_trylock (futex, 2) + +#define lll_cond_trylock(lock)	__lll_cond_trylock (&(lock)) + + +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; + +#define lll_lock(lock, private) \ +  (void) ({								      \ +    int *__futex = &(lock);						      \ +    if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 1, 0),\ +			  0) != 0)					      \ +      {									      \ +	if (__builtin_constant_p (private) && (private) == LLL_PRIVATE)	      \ +	  __lll_lock_wait_private (__futex);				      \ +	else								      \ +	  __lll_lock_wait (__futex, private);				      \ +      }									      \ +  }) + +#define lll_robust_lock(lock, id, private) \ +  ({									      \ +    int *__futex = &(lock);						      \ +    int __val = 0;							      \ +    if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \ +								0), 0))	      \ +      __val = __lll_robust_lock_wait (__futex, private);		      \ +    __val;								      \ +  }) + +#define lll_cond_lock(lock, private) \ +  (void) ({								      \ +    int *__futex = &(lock);						      \ +    if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 2, 0),\ +			  0) != 0)					      \ +      __lll_lock_wait (__futex, private);				      \ +  }) + +#define lll_robust_cond_lock(lock, id, private) \ +  ({									      \ +    int *__futex = &(lock);						      \ +    int __val = 0;							      \ +    int __id = id | FUTEX_WAITERS;					      \ +    if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, __id,\ +								0), 0))	      \ +      __val = __lll_robust_lock_wait (__futex, private);		      \ +    __val;								      \ +  }) + + +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; + +#define lll_timedlock(lock, abstime, private) \ +  ({									      \ +    int *__futex = &(lock);						      \ +    int __val = 0;							      \ +    if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 1, 0),\ +			  0) != 0)					      \ +      __val = __lll_timedlock_wait (__futex, abstime, private);		      \ +    __val;								      \ +  }) + +#define lll_robust_timedlock(lock, abstime, id, private) \ +  ({									      \ +    int *__futex = &(lock);						      \ +    int __val = 0;							      \ +    if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \ +								0), 0))	      \ +      __val = __lll_robust_timedlock_wait (__futex, abstime, private);	      \ +    __val;								      \ +  }) + +#define lll_unlock(lock, private) \ +  ((void) ({								      \ +    int *__futex = &(lock);						      \ +    int __val = atomic_exchange_rel (__futex, 0);			      \ +    if (__builtin_expect (__val > 1, 0))				      \ +      lll_futex_wake (__futex, 1, private);				      \ +  })) + +#define lll_robust_unlock(lock, private) \ +  ((void) ({								      \ +    int *__futex = &(lock);						      \ +    int __val = atomic_exchange_rel (__futex, 0);			      \ +    if (__builtin_expect (__val & FUTEX_WAITERS, 0))			      \ +      lll_futex_wake (__futex, 1, private);				      \ +  })) + +#define lll_islocked(futex) \ +  (futex != 0) + + +/* Initializers for lock.  */ +#define LLL_LOCK_INITIALIZER		(0) +#define LLL_LOCK_INITIALIZER_LOCKED	(1) + +/* The states of a lock are: +    0  -  untaken +    1  -  taken by one user +   >1  -  taken by more users */ + +/* The kernel notifies a process which uses CLONE_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(tid) \ +  do {									      \ +    __typeof (tid) __tid;						      \ +    while ((__tid = (tid)) != 0)					      \ +      lll_futex_wait (&(tid), __tid, LLL_SHARED);			      \ +  } while (0) + +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;								      \ +  }) + +#endif	/* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/not-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/not-cancel.h new file mode 100644 index 000000000..acf1a617e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/not-cancel.h @@ -0,0 +1 @@ +#include "../i386/not-cancel.h" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S new file mode 100644 index 000000000..675a997e9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S @@ -0,0 +1,9 @@ +/* We want an #include_next, but we are the main source file. +   So, #include ourselves and in that incarnation we can use #include_next.  */ +#ifndef INCLUDED_SELF +# define INCLUDED_SELF +# include <clone.S> +#else +# define RESET_PID +# include_next <clone.S> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/pt-vfork.S new file mode 100644 index 000000000..61651fd97 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/pt-vfork.S @@ -0,0 +1,49 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + +   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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#define _ERRNO_H	1 +#include <bits/errno.h> +#include <bits/kernel-features.h> +#include <tcb-offsets.h> + +/* Clone the calling process, but without copying the whole address space. +   The calling process is suspended until the new process exits or is +   replaced by a call to `execve'.  Return -1 for errors, 0 to the new process, +   and the process ID of the new process to the old process.  */ + +ENTRY (__vfork) +	lwz	0,PID(2) +	neg	0,0 +	stw	0,PID(2) + +	DO_CALL (SYS_ify (vfork)) + +	cmpwi	1,3,0 +	beqlr-	1 + +	lwz	0,PID(2) +	neg	0,0 +	stw	0,PID(2) + +	PSEUDO_RET + +PSEUDO_END (__vfork) + +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h new file mode 100644 index 000000000..88b24e7d9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h @@ -0,0 +1,119 @@ +/* Cancellable system call stubs.  Linux/PowerPC version. +   Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Franz Sirl <Franz.Sirl-kernel@lauterbach.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, write to the Free +   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA +   02110-1301 USA.  */ + +#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)				\ +  .section ".text";							\ +  ENTRY (name)								\ +    SINGLE_THREAD_P;							\ +    bne- .Lpseudo_cancel;						\ +  .type __##syscall_name##_nocancel,@function;				\ +  .globl __##syscall_name##_nocancel;					\ +  __##syscall_name##_nocancel:						\ +    DO_CALL (SYS_ify (syscall_name));					\ +    PSEUDO_RET;								\ +  .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;	\ +  .Lpseudo_cancel:							\ +    stwu 1,-48(1);							\ +    cfi_adjust_cfa_offset (48);						\ +    mflr 9;								\ +    stw 9,52(1);							\ +    cfi_offset (lr, 4);							\ +    DOCARGS_##args;	/* save syscall args around CENABLE.  */	\ +    CENABLE;								\ +    stw 3,16(1);	/* store CENABLE return value (MASK).  */	\ +    UNDOCARGS_##args;	/* restore syscall args.  */			\ +    DO_CALL (SYS_ify (syscall_name));					\ +    mfcr 0;		/* save CR/R3 around CDISABLE.  */		\ +    stw 3,8(1);								\ +    stw 0,12(1);							\ +    lwz 3,16(1);	/* pass MASK to CDISABLE.  */			\ +    CDISABLE;								\ +    lwz 4,52(1);							\ +    lwz 0,12(1);	/* restore CR/R3. */				\ +    lwz 3,8(1);								\ +    mtlr 4;								\ +    mtcr 0;								\ +    addi 1,1,48; + +# define DOCARGS_0 +# define UNDOCARGS_0 + +# define DOCARGS_1	stw 3,20(1); DOCARGS_0 +# define UNDOCARGS_1	lwz 3,20(1); UNDOCARGS_0 + +# define DOCARGS_2	stw 4,24(1); DOCARGS_1 +# define UNDOCARGS_2	lwz 4,24(1); UNDOCARGS_1 + +# define DOCARGS_3	stw 5,28(1); DOCARGS_2 +# define UNDOCARGS_3	lwz 5,28(1); UNDOCARGS_2 + +# define DOCARGS_4	stw 6,32(1); DOCARGS_3 +# define UNDOCARGS_4	lwz 6,32(1); UNDOCARGS_3 + +# define DOCARGS_5	stw 7,36(1); DOCARGS_4 +# define UNDOCARGS_5	lwz 7,36(1); UNDOCARGS_4 + +# define DOCARGS_6	stw 8,40(1); DOCARGS_5 +# define UNDOCARGS_6	lwz 8,40(1); UNDOCARGS_5 + +# ifdef IS_IN_libpthread +#  define CENABLE	bl __pthread_enable_asynccancel@local +#  define CDISABLE	bl __pthread_disable_asynccancel@local +# elif !defined NOT_IN_libc +#  define CENABLE	bl __libc_enable_asynccancel@local +#  define CDISABLE	bl __libc_disable_asynccancel@local +# elif defined IS_IN_librt +#  define CENABLE	bl __librt_enable_asynccancel@local +#  define CDISABLE	bl __librt_disable_asynccancel@local +# else +#  error Unsupported library +# endif + +# ifndef __ASSEMBLER__ +#  define SINGLE_THREAD_P						\ +  __builtin_expect (THREAD_GETMEM (THREAD_SELF,				\ +				   header.multiple_threads) == 0, 1) +# else +#  define SINGLE_THREAD_P						\ +  lwz 10,MULTIPLE_THREADS_OFFSET(2);					\ +  cmpwi 10,0 +# 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/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S new file mode 100644 index 000000000..eed2a8f1a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S @@ -0,0 +1,57 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + +   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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#define _ERRNO_H	1 +#include <bits/errno.h> +#include <bits/kernel-features.h> +#include <tcb-offsets.h> + +/* Clone the calling process, but without copying the whole address space. +   The calling process is suspended until the new process exits or is +   replaced by a call to `execve'.  Return -1 for errors, 0 to the new process, +   and the process ID of the new process to the old process.  */ + +ENTRY (__vfork) +	lwz	0,PID(2) +	cmpwi	0,0,0 +	neg	0,0 +	bne-	0,1f +	lis	0,0x8000 +1:	stw	0,PID(2) + +	DO_CALL (SYS_ify (vfork)) + +	cmpwi	1,3,0 +	beqlr-	1 + +	lwz	0,PID(2) +	/* Cannot use clrlwi. here, because cr0 needs to be preserved +	   until PSEUDO_RET.  */ +	clrlwi	4,0,1 +	cmpwi	1,4,0 +	beq-	1,1f +	neg	4,0 +1:	stw	4,PID(2) + +	PSEUDO_RET + +PSEUDO_END (__vfork) +libc_hidden_def (__vfork) +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S new file mode 100644 index 000000000..675a997e9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S @@ -0,0 +1,9 @@ +/* We want an #include_next, but we are the main source file. +   So, #include ourselves and in that incarnation we can use #include_next.  */ +#ifndef INCLUDED_SELF +# define INCLUDED_SELF +# include <clone.S> +#else +# define RESET_PID +# include_next <clone.S> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/pt-vfork.S new file mode 100644 index 000000000..e5b7b535c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/pt-vfork.S @@ -0,0 +1,49 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + +   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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#define _ERRNO_H	1 +#include <bits/errno.h> +#include <bits/kernel-features.h> +#include <tcb-offsets.h> + +/* Clone the calling process, but without copying the whole address space. +   The calling process is suspended until the new process exits or is +   replaced by a call to `execve'.  Return -1 for errors, 0 to the new process, +   and the process ID of the new process to the old process.  */ + +ENTRY (__vfork) +	lwz	0,PID(13) +	neg	0,0 +	stw	0,PID(13) + +	DO_CALL (SYS_ify (vfork)) + +	cmpwi	1,3,0 +	beqlr-	1 + +	lwz	0,PID(13) +	neg	0,0 +	stw	0,PID(13) + +	PSEUDO_RET + +PSEUDO_END (__vfork) + +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h new file mode 100644 index 000000000..707765ab5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h @@ -0,0 +1,125 @@ +/* Cancellable system call stubs.  Linux/PowerPC64 version. +   Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Franz Sirl <Franz.Sirl-kernel@lauterbach.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, write to the Free +   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA +   02110-1301 USA.  */ + +#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 + +# ifdef HAVE_ASM_GLOBAL_DOT_NAME +#  define DASHDASHPFX(str) .__##str +# else +#  define DASHDASHPFX(str) __##str +# endif + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args)				\ +  .section ".text";							\ +  ENTRY (name)								\ +    SINGLE_THREAD_P;							\ +    bne- .Lpseudo_cancel;						\ +  .type DASHDASHPFX(syscall_name##_nocancel),@function;			\ +  .globl DASHDASHPFX(syscall_name##_nocancel);				\ +  DASHDASHPFX(syscall_name##_nocancel):					\ +    DO_CALL (SYS_ify (syscall_name));					\ +    PSEUDO_RET;								\ +  .size DASHDASHPFX(syscall_name##_nocancel),.-DASHDASHPFX(syscall_name##_nocancel);	\ +  .Lpseudo_cancel:							\ +    stdu 1,-128(1);							\ +    cfi_adjust_cfa_offset (128);					\ +    mflr 9;								\ +    std  9,128+16(1);							\ +    cfi_offset (lr, 16);						\ +    DOCARGS_##args;	/* save syscall args around CENABLE.  */	\ +    CENABLE;								\ +    std  3,72(1);	/* store CENABLE return value (MASK).  */	\ +    UNDOCARGS_##args;	/* restore syscall args.  */			\ +    DO_CALL (SYS_ify (syscall_name));					\ +    mfcr 0;		/* save CR/R3 around CDISABLE.  */		\ +    std  3,64(1);							\ +    std  0,8(1);							\ +    ld   3,72(1);	/* pass MASK to CDISABLE.  */			\ +    CDISABLE;								\ +    ld   9,128+16(1);							\ +    ld   0,8(1);	/* restore CR/R3. */				\ +    ld   3,64(1);							\ +    mtlr 9;								\ +    mtcr 0;								\ +    addi 1,1,128; + +# define DOCARGS_0 +# define UNDOCARGS_0 + +# define DOCARGS_1	std 3,80(1); DOCARGS_0 +# define UNDOCARGS_1	ld 3,80(1); UNDOCARGS_0 + +# define DOCARGS_2	std 4,88(1); DOCARGS_1 +# define UNDOCARGS_2	ld 4,88(1); UNDOCARGS_1 + +# define DOCARGS_3	std 5,96(1); DOCARGS_2 +# define UNDOCARGS_3	ld 5,96(1); UNDOCARGS_2 + +# define DOCARGS_4	std 6,104(1); DOCARGS_3 +# define UNDOCARGS_4	ld 6,104(1); UNDOCARGS_3 + +# define DOCARGS_5	std 7,112(1); DOCARGS_4 +# define UNDOCARGS_5	ld 7,112(1); UNDOCARGS_4 + +# define DOCARGS_6	std 8,120(1); DOCARGS_5 +# define UNDOCARGS_6	ld 8,120(1); UNDOCARGS_5 + +# ifdef IS_IN_libpthread +#  define CENABLE	bl JUMPTARGET(__pthread_enable_asynccancel) +#  define CDISABLE	bl JUMPTARGET(__pthread_disable_asynccancel) +# elif !defined NOT_IN_libc +#  define CENABLE	bl JUMPTARGET(__libc_enable_asynccancel) +#  define CDISABLE	bl JUMPTARGET(__libc_disable_asynccancel) +# elif defined IS_IN_librt +#  define CENABLE	bl JUMPTARGET(__librt_enable_asynccancel) +#  define CDISABLE	bl JUMPTARGET(__librt_disable_asynccancel) +# else +#  error Unsupported library +# endif + +# ifndef __ASSEMBLER__ +#  define SINGLE_THREAD_P						\ +  __builtin_expect (THREAD_GETMEM (THREAD_SELF,				\ +				   header.multiple_threads) == 0, 1) +# else +#   define SINGLE_THREAD_P						\ +  lwz   10,MULTIPLE_THREADS_OFFSET(13);				\ +  cmpwi 10,0 +# 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/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_create.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_create.c new file mode 100644 index 000000000..172223af3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_create.c @@ -0,0 +1 @@ +#include "../x86_64/timer_create.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_delete.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_delete.c new file mode 100644 index 000000000..537516e0a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_delete.c @@ -0,0 +1 @@ +#include "../x86_64/timer_delete.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_getoverr.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_getoverr.c new file mode 100644 index 000000000..3f21a73c9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_getoverr.c @@ -0,0 +1 @@ +#include "../x86_64/timer_getoverr.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_gettime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_gettime.c new file mode 100644 index 000000000..a50143adc --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_gettime.c @@ -0,0 +1 @@ +#include "../x86_64/timer_gettime.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_settime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_settime.c new file mode 100644 index 000000000..37baeffac --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/timer_settime.c @@ -0,0 +1 @@ +#include "../x86_64/timer_settime.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S new file mode 100644 index 000000000..26885bb95 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S @@ -0,0 +1,55 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + +   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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#define _ERRNO_H	1 +#include <bits/errno.h> +#include <bits/kernel-features.h> +#include <tcb-offsets.h> + +/* Clone the calling process, but without copying the whole address space. +   The calling process is suspended until the new process exits or is +   replaced by a call to `execve'.  Return -1 for errors, 0 to the new process, +   and the process ID of the new process to the old process.  */ + +ENTRY (__vfork) +	lwz	0,PID(13) +	cmpwi	0,0,0 +	neg	0,0 +	bne-	0,1f +	lis	0,0x8000 +1:	stw	0,PID(13) + +	DO_CALL (SYS_ify (vfork)) + +	cmpwi	1,3,0 +	beqlr-	1 + +	lwz	0,PID(13) +	clrlwi	4,0,1 +	cmpwi	1,4,0 +	beq-	1,1f +	neg	4,0 +1:	stw	4,PID(13) + +	PSEUDO_RET + +PSEUDO_END (__vfork) +libc_hidden_def (__vfork) +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pt-longjmp.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pt-longjmp.c new file mode 100644 index 000000000..b6d6b3d55 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pt-longjmp.c @@ -0,0 +1,37 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <setjmp.h> +#include <stdlib.h> +#include <bits/wordsize.h> +#include "pthreadP.h" + +void +__vmx_longjmp (jmp_buf env, int val) +{ +  __libc_longjmp (env, val); +} + +void +__vmx_siglongjmp (jmp_buf env, int val) +{ +  __libc_siglongjmp (env, val); +} +weak_alias(__vmx_longjmp, longjmp) +weak_alias(__vmx_siglongjmp, siglongjmp) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pthread_once.c new file mode 100644 index 000000000..bc5f3f0f1 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pthread_once.c @@ -0,0 +1,101 @@ +/* Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#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 +attribute_protected +__pthread_once (pthread_once_t *once_control, void (*init_routine) (void)) +{ +  for (;;) +    { +      int oldval; +      int newval; +      int tmp; + +      /* Pseudo code: +	 newval = __fork_generation | 1; +	 oldval = *once_control; +	 if ((oldval & 2) == 0) +	   *once_control = newval; +	 Do this atomically. +      */ +      newval = __fork_generation | 1; +      __asm __volatile ("1:	lwarx	%0,0,%3\n" +			"	andi.	%1,%0,2\n" +			"	bne	2f\n" +			"	stwcx.	%4,0,%3\n" +			"	bne	1b\n" +			"2:	isync" +			: "=&r" (oldval), "=&r" (tmp), "=m" (*once_control) +			: "r" (once_control), "r" (newval), "m" (*once_control) +			: "cr0"); + +      /* Check if the initializer has already been done.  */ +      if ((oldval & 2) != 0) +	return 0; + +      /* Check if another thread already runs the initializer.	*/ +      if ((oldval & 1) == 0) +	break; + +      /* Check whether the initializer execution was interrupted by a fork.  */ +      if (oldval != newval) +	break; + +      /* Same generation, some other thread was faster. Wait.  */ +      lll_futex_wait (once_control, oldval, LLL_PRIVATE); +    } + + +  /* 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 to take the bottom 2 bits from 01 to 10.  */ +  atomic_increment (once_control); + +  /* Wake up all other threads.  */ +  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE); + +  return 0; +} +weak_alias (__pthread_once, pthread_once) +strong_alias (__pthread_once, __pthread_once_internal) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pthread_spin_unlock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pthread_spin_unlock.c new file mode 100644 index 000000000..90f2dc67c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pthread_spin_unlock.c @@ -0,0 +1,29 @@ +/* pthread_spin_unlock -- unlock a spin lock.  PowerPC version. +   Copyright (C) 2007 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "pthreadP.h" +#include <lowlevellock.h> + +int +pthread_spin_unlock (pthread_spinlock_t *lock) +{ +  __asm __volatile (__lll_rel_instr ::: "memory"); +  *lock = 0; +  return 0; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/sem_post.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/sem_post.c new file mode 100644 index 000000000..0082c570a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/sem_post.c @@ -0,0 +1,47 @@ +/* sem_post -- post to a POSIX semaphore.  Powerpc version. +   Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <internaltypes.h> +#include <semaphore.h> + +int +__new_sem_post (sem_t *sem) +{ +  struct new_sem *isem = (struct new_sem *) sem; + +  __asm __volatile (__lll_rel_instr ::: "memory"); +  atomic_increment (&isem->value); +  __asm __volatile (__lll_acq_instr ::: "memory"); +  if (isem->nwaiters > 0) +    { +      int err = lll_futex_wake (&isem->value, 1, +				isem->private ^ FUTEX_PRIVATE_FLAG); +      if (__builtin_expect (err, 0) < 0) +	{ +	  __set_errno (-err); +	  return -1; +	} +    } +  return 0; +} +weak_alias(__new_sem_post, sem_post) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-accept.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-accept.S new file mode 100644 index 000000000..24062101d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-accept.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_accept +#error Missing definition of NR_accept needed for cancellation. +#endif +PSEUDO (__libc_accept, accept, 3) +ret +PSEUDO_END(__libc_accept) +libpthread_hidden_def (__libc_accept) +weak_alias (__libc_accept, __accept) +libpthread_hidden_weak (__accept) +weak_alias (__libc_accept, accept) +libpthread_hidden_weak (accept) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-close.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-close.S new file mode 100644 index 000000000..ab32ca598 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-close.S @@ -0,0 +1,9 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_close, close, 1) +ret +PSEUDO_END (__libc_close) +libpthread_hidden_def (__libc_close) +weak_alias (__libc_close, __close) +libpthread_hidden_weak (__close) +weak_alias (__libc_close, close) +libpthread_hidden_weak (close) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-connect.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-connect.S new file mode 100644 index 000000000..b5124f8ec --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-connect.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_connect +#error Missing definition of NR_connect needed for cancellation. +#endif +PSEUDO (__libc_connect, connect, 3) +ret +PSEUDO_END(__libc_connect) +libpthread_hidden_def (__libc_connect) +weak_alias (__libc_connect, __connect) +libpthread_hidden_weak (__connect) +weak_alias (__libc_connect, connect) +libpthread_hidden_weak (connect) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fcntl.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fcntl.c new file mode 100644 index 000000000..0a8fd3cc2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fcntl.c @@ -0,0 +1 @@ +#include <../../../../../../libc/sysdeps/linux/common/__syscall_fcntl.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fork.c new file mode 100644 index 000000000..3e1b70f86 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fork.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <unistd.h> + +extern int __libc_fork (void); + +pid_t +__fork (void) +{ +  return __libc_fork (); +} +strong_alias (__fork, fork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fsync.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fsync.c new file mode 100644 index 000000000..6ec4821c7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-fsync.c @@ -0,0 +1,2 @@ +#include <pthreadP.h> +#include <../../../../../../libc/sysdeps/linux/common/fsync.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-llseek.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-llseek.c new file mode 100644 index 000000000..1d0d57870 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-llseek.c @@ -0,0 +1,3 @@ +#include <pthreadP.h> +#define libc_hidden libpthread_hidden +#include <../../../../../../libc/sysdeps/linux/common/llseek.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-lseek.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-lseek.S new file mode 100644 index 000000000..4db71722a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-lseek.S @@ -0,0 +1,7 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_lseek, lseek, 3) +ret +PSEUDO_END (__libc_lseek) +libpthread_hidden_def (__libc_lseek) +weak_alias (__libc_lseek, lseek) +libpthread_hidden_weak (lseek) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msgrcv.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msgrcv.c new file mode 100644 index 000000000..3bb9d53df --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msgrcv.c @@ -0,0 +1,2 @@ +#define L_msgrcv +#include <../../../../../../libc/misc/sysvipc/msgq.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msgsnd.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msgsnd.c new file mode 100644 index 000000000..1566f65f4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msgsnd.c @@ -0,0 +1,2 @@ +#define L_msgsnd +#include <../../../../../../libc/misc/sysvipc/msgq.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msync.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msync.S new file mode 100644 index 000000000..640270ad9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-msync.S @@ -0,0 +1,7 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_msync, msync, 3) +ret +PSEUDO_END(__libc_msync) +libpthread_hidden_def (__libc_msync) +weak_alias (__libc_msync, msync) +libpthread_hidden_weak (msync) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-nanosleep.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-nanosleep.S new file mode 100644 index 000000000..08d8f0150 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-nanosleep.S @@ -0,0 +1,9 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_nanosleep, nanosleep, 3) +ret +PSEUDO_END (__libc_nanosleep) +libpthread_hidden_def (__libc_nanosleep) +weak_alias (__libc_nanosleep, __nanosleep) +libpthread_hidden_weak (__nanosleep) +weak_alias (__libc_nanosleep, nanosleep) +libpthread_hidden_weak (nanosleep) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-open.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-open.S new file mode 100644 index 000000000..39ed92cc7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-open.S @@ -0,0 +1,9 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_open, open, 3) +ret +PSEUDO_END (__libc_open) +libpthread_hidden_def (__libc_open) +weak_alias (__libc_open, __open) +libpthread_hidden_weak (__open) +weak_alias (__libc_open, open) +libpthread_hidden_weak (open) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-open64.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-open64.c new file mode 100644 index 000000000..2029539a7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-open64.c @@ -0,0 +1 @@ +#include <../../../../../../libc/sysdeps/linux/common/open64.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-pause.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-pause.S new file mode 100644 index 000000000..c6cb57180 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-pause.S @@ -0,0 +1,7 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_pause, pause, 0) +ret +PSEUDO_END (__libc_pause) +libpthread_hidden_def (__libc_pause) +weak_alias (__libc_pause, pause) +libpthread_hidden_weak (pause) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-pread_pwrite.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-pread_pwrite.c new file mode 100644 index 000000000..f32c0a670 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-pread_pwrite.c @@ -0,0 +1 @@ +#include "pread_write.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-raise.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-raise.c new file mode 100644 index 000000000..d256ebcb0 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-raise.c @@ -0,0 +1,52 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include <signal.h> +#include <sysdep.h> +#include <tls.h> +#include <bits/kernel-features.h> + + +int +raise ( +     int sig) +{ +#if __ASSUME_TGKILL || defined __NR_tgkill +  /* raise is an async-safe function.  It could be called while the +     fork function temporarily invalidated the PID field.  Adjust for +     that.  */ +  pid_t pid = THREAD_GETMEM (THREAD_SELF, pid); +  if (__builtin_expect (pid < 0, 0)) +    pid = -pid; +#endif + +#if __ASSUME_TGKILL +  return INLINE_SYSCALL (tgkill, 3, pid, THREAD_GETMEM (THREAD_SELF, tid), +			 sig); +#else +# ifdef __NR_tgkill +  int res = INLINE_SYSCALL (tgkill, 3, pid, THREAD_GETMEM (THREAD_SELF, tid), +			    sig); +  if (res != -1 || errno != ENOSYS) +    return res; +# endif +  return INLINE_SYSCALL (tkill, 2, THREAD_GETMEM (THREAD_SELF, tid), sig); +#endif +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-read.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-read.S new file mode 100644 index 000000000..623ba27a8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-read.S @@ -0,0 +1,9 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_read, read, 3) +ret +PSEUDO_END (__libc_read) +libpthread_hidden_def (__libc_read) +weak_alias (__libc_read, __read) +libpthread_hidden_weak (__read) +weak_alias (__libc_read, read) +libpthread_hidden_weak (read) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recv.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recv.S new file mode 100644 index 000000000..6d2e3c2d6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recv.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_recv +#error Missing definition of NR_recv needed for cancellation. +#endif +PSEUDO (__libc_recv, recv, 4) +ret +PSEUDO_END(__libc_recv) +libpthread_hidden_def (__libc_recv) +weak_alias (__libc_recv, __recv) +libpthread_hidden_weak (__recv) +weak_alias (__libc_recv, recv) +libpthread_hidden_weak (recv) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recvfrom.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recvfrom.S new file mode 100644 index 000000000..96aeeaa3d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recvfrom.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_recvfrom +#error Missing definition of NR_recvfrom needed for cancellation. +#endif +PSEUDO (__libc_recvfrom, recvfrom, 6) +ret +PSEUDO_END(__libc_recvfrom) +libpthread_hidden_def (__libc_recvfrom) +weak_alias (__libc_recvfrom, __recvfrom) +libpthread_hidden_weak (__recvfrom) +weak_alias (__libc_recvfrom, recvfrom) +libpthread_hidden_weak (recvfrom) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recvmsg.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recvmsg.S new file mode 100644 index 000000000..f7161e47c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-recvmsg.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_recvmsg +#error Missing definition of NR_recvmsg needed for cancellation. +#endif +PSEUDO (__libc_recvmsg, recvmsg, 3) +ret +PSEUDO_END(__libc_recvmsg) +libpthread_hidden_def (__libc_recvmsg) +weak_alias (__libc_recvmsg, __recvmsg) +libpthread_hidden_weak (__recvmsg) +weak_alias (__libc_recvmsg, recvmsg) +libpthread_hidden_weak (recvmsg) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-send.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-send.S new file mode 100644 index 000000000..76bed39ec --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-send.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_send +#error Missing definition of NR_send needed for cancellation. +#endif +PSEUDO (__libc_send, send, 4) +ret +PSEUDO_END (__libc_send) +libpthread_hidden_def (__libc_send) +weak_alias (__libc_send, __send) +libpthread_hidden_weak (__send) +weak_alias (__libc_send, send) +libpthread_hidden_weak (send) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sendmsg.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sendmsg.S new file mode 100644 index 000000000..d17096eae --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sendmsg.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_sendmsg +#error Missing definition of NR_sendmsg needed for cancellation. +#endif +PSEUDO (__libc_sendmsg, sendmsg, 3) +ret +PSEUDO_END(__libc_sendmsg) +libpthread_hidden_def (__libc_sendmsg) +weak_alias (__libc_sendmsg, __sendmsg) +libpthread_hidden_weak (__sendmsg) +weak_alias (__libc_sendmsg, sendmsg) +libpthread_hidden_weak (sendmsg) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sendto.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sendto.S new file mode 100644 index 000000000..d07a71f8a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sendto.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_sendto +#error Missing definition of NR_sendto needed for cancellation. +#endif +PSEUDO (__libc_sendto, sendto, 6) +ret +PSEUDO_END(__libc_sendto) +libpthread_hidden_def (__libc_sendto) +weak_alias (__libc_sendto, __sendto) +libpthread_hidden_weak (__sendto) +weak_alias (__libc_sendto, sendto) +libpthread_hidden_weak (sendto) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sigwait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sigwait.c new file mode 100644 index 000000000..bde0a9292 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sigwait.c @@ -0,0 +1,2 @@ +#include <pthreadP.h> +#include "../../../../../../libc/signal/sigwait.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sleep.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sleep.c new file mode 100644 index 000000000..9e948adce --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-sleep.c @@ -0,0 +1,2 @@ +#include <pthreadP.h> +#include <../../../../../../libc/unistd/sleep.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-tcdrain.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-tcdrain.c new file mode 100644 index 000000000..07c1f8233 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-tcdrain.c @@ -0,0 +1 @@ +#include <../../../../../../libc/termios/tcdrain.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-wait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-wait.c new file mode 100644 index 000000000..a05c3eb49 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-wait.c @@ -0,0 +1,2 @@ +#include <pthreadP.h> +#include <../../../../../../libc/sysdeps/linux/common/wait.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-waitpid.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-waitpid.c new file mode 100644 index 000000000..8461c3ff2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-waitpid.c @@ -0,0 +1 @@ +#include <../../../../../../libc/sysdeps/linux/common/waitpid.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pt-write.S b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-write.S new file mode 100644 index 000000000..6bc666779 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-write.S @@ -0,0 +1,9 @@ +#include <sysdep-cancel.h> +PSEUDO (__libc_write, write, 3) +ret +PSEUDO_END (__libc_write) +libpthread_hidden_def (__libc_write) +weak_alias (__libc_write, __write) +libpthread_hidden_weak (__write) +weak_alias (__libc_write, write) +libpthread_hidden_weak (write) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym new file mode 100644 index 000000000..46fbd0de7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym @@ -0,0 +1,8 @@ +#include <pthreadP.h> + +-- These PI macros are used by assembly code. + +MUTEX_KIND	offsetof (pthread_mutex_t, __data.__kind) +ROBUST_BIT	PTHREAD_MUTEX_ROBUST_NORMAL_NP +PI_BIT		PTHREAD_MUTEX_PRIO_INHERIT_NP +PS_BIT		PTHREAD_MUTEX_PSHARED_BIT diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c new file mode 100644 index 000000000..2ec2f3d74 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <assert.h> +#include <errno.h> +#include <pthreadP.h> +#include <string.h> +#include <sysdep.h> +#include <sys/types.h> + + +int +pthread_attr_getaffinity_np(const pthread_attr_t *attr, size_t cpusetsize, +				cpu_set_t *cpuset) +{ +  const struct pthread_attr *iattr; + +  assert (sizeof (*attr) >= sizeof (struct pthread_attr)); +  iattr = (const struct pthread_attr *) attr; + +  if (iattr->cpuset != NULL) +    { +      /* Check whether there are any bits set beyond the limits +	 the user requested.  */ +      for (size_t cnt = cpusetsize; cnt < iattr->cpusetsize; ++cnt) +	if (((char *) iattr->cpuset)[cnt] != 0) +	  return EINVAL; + +      void *p = mempcpy (cpuset, iattr->cpuset, iattr->cpusetsize); +      if (cpusetsize > iattr->cpusetsize) +	memset (p, '\0', cpusetsize - iattr->cpusetsize); +    } +  else +    /* We have no information.  */ +    memset (cpuset, -1, cpusetsize); + +  return 0; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c new file mode 100644 index 000000000..609ee2ad1 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c @@ -0,0 +1,80 @@ +/* Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <assert.h> +#include <errno.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <pthreadP.h> + + +/* Defined in pthread_setaffinity.c.  */ +extern size_t __kernel_cpumask_size attribute_hidden; +extern int __determine_cpumask_size (pid_t tid); +libpthread_hidden_proto(__determine_cpumask_size) + +int +pthread_attr_setaffinity_np (pthread_attr_t *attr, size_t cpusetsize, +				const cpu_set_t *cpuset) +{ +  struct pthread_attr *iattr; + +  assert (sizeof (*attr) >= sizeof (struct pthread_attr)); +  iattr = (struct pthread_attr *) attr; + +  if (cpuset == NULL || cpusetsize == 0) +    { +      free (iattr->cpuset); +      iattr->cpuset = NULL; +      iattr->cpusetsize = 0; +    } +  else +    { +      if (__kernel_cpumask_size == 0) +	{ +	  int res = __determine_cpumask_size (THREAD_SELF->tid); +	  if (res != 0) +	    /* Some serious problem.  */ +	    return res; +	} + +      /* Check whether the new bitmask has any bit set beyond the +	 last one the kernel accepts.  */ +      for (size_t cnt = __kernel_cpumask_size; cnt < cpusetsize; ++cnt) +	if (((char *) cpuset)[cnt] != '\0') +	  /* Found a nonzero byte.  This means the user request cannot be +	     fulfilled.  */ +	  return EINVAL; + +      if (iattr->cpusetsize != cpusetsize) +	{ +	  void *newp = (cpu_set_t *) realloc (iattr->cpuset, cpusetsize); +	  if (newp == NULL) +	    return ENOMEM; + +	  iattr->cpuset = newp; +	  iattr->cpusetsize = cpusetsize; +	} + +      memcpy (iattr->cpuset, cpuset, cpusetsize); +    } + +  return 0; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getaffinity.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getaffinity.c new file mode 100644 index 000000000..affcc6a65 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getaffinity.c @@ -0,0 +1,46 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include <limits.h> +#include <pthreadP.h> +#include <string.h> +#include <sysdep.h> +#include <sys/param.h> +#include <sys/types.h> + + +int +__pthread_getaffinity_np (pthread_t th, size_t cpusetsize, cpu_set_t *cpuset) +{ +  const struct pthread *pd = (const struct pthread *) th; + +  INTERNAL_SYSCALL_DECL (err); +  int res = INTERNAL_SYSCALL (sched_getaffinity, err, 3, pd->tid, +			      MIN (INT_MAX, cpusetsize), cpuset); +  if (INTERNAL_SYSCALL_ERROR_P (res, err)) +    return INTERNAL_SYSCALL_ERRNO (res, err); + +  /* Clean the rest of the memory the kernel didn't do.  */ +  memset ((char *) cpuset + res, '\0', cpusetsize - res); + +  return 0; +} +strong_alias(__pthread_getaffinity_np, pthread_getaffinity_np) + diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c new file mode 100644 index 000000000..9e28f69fd --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2000, 2001, 2002, 2003 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; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +#include <errno.h> +#include <pthreadP.h> +#include <sys/time.h> +#include <tls.h> + + +int +pthread_getcpuclockid ( +     pthread_t threadid, +     clockid_t *clockid) +{ +  struct pthread *pd = (struct pthread *) threadid; + +  /* Make sure the descriptor is valid.  */ +  if (INVALID_TD_P (pd)) +    /* Not a valid thread handle.  */ +    return ESRCH; + +#ifdef CLOCK_THREAD_CPUTIME_ID +  /* We need to store the thread ID in the CLOCKID variable together +     with a number identifying the clock.  We reserve the low 3 bits +     for the clock ID and the rest for the thread ID.  This is +     problematic if the thread ID is too large.  But 29 bits should be +     fine. + +     If some day more clock IDs are needed the ID part can be +     enlarged.  The IDs are entirely internal.  */ +  if (pd->tid >= 1 << (8 * sizeof (*clockid) - CLOCK_IDFIELD_SIZE)) +    return ERANGE; + +  /* Store the number.  */ +  *clockid = CLOCK_THREAD_CPUTIME_ID | (pd->tid << CLOCK_IDFIELD_SIZE); + +  return 0; +#else +  /* We don't have a timer for that.  */ +  return ENOENT; +#endif +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_kill.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_kill.c new file mode 100644 index 000000000..3a70c3764 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_kill.c @@ -0,0 +1,78 @@ +/* Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include <signal.h> +#include <pthreadP.h> +#include <tls.h> +#include <sysdep.h> +#include <bits/kernel-features.h> + + +int +__pthread_kill ( +     pthread_t threadid, +     int signo) +{ +  struct pthread *pd = (struct pthread *) threadid; + +  /* Make sure the descriptor is valid.  */ +  if (DEBUGGING_P && INVALID_TD_P (pd)) +    /* Not a valid thread handle.  */ +    return ESRCH; + +  /* Force load of pd->tid into local variable or register.  Otherwise +     if a thread exits between ESRCH test and tgkill, we might return +     EINVAL, because pd->tid would be cleared by the kernel.  */ +  pid_t tid = atomic_forced_read (pd->tid); +  if (__builtin_expect (tid <= 0, 0)) +    /* Not a valid thread handle.  */ +    return ESRCH; + +  /* Disallow sending the signal we use for cancellation, timers, for +     for the setxid implementation.  */ +  if (signo == SIGCANCEL || signo == SIGTIMER || signo == SIGSETXID) +    return EINVAL; + +  /* We have a special syscall to do the work.  */ +  INTERNAL_SYSCALL_DECL (err); + +  /* One comment: The PID field in the TCB can temporarily be changed +     (in fork).  But this must not affect this code here.  Since this +     function would have to be called while the thread is executing +     fork, it would have to happen in a signal handler.  But this is +     no allowed, pthread_kill is not guaranteed to be async-safe.  */ +  int val; +#if __ASSUME_TGKILL +  val = INTERNAL_SYSCALL (tgkill, err, 3, THREAD_GETMEM (THREAD_SELF, pid), +			  tid, signo); +#else +# ifdef __NR_tgkill +  val = INTERNAL_SYSCALL (tgkill, err, 3, THREAD_GETMEM (THREAD_SELF, pid), +			  tid, signo); +  if (INTERNAL_SYSCALL_ERROR_P (val, err) +      && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS) +# endif +    val = INTERNAL_SYSCALL (tkill, err, 2, tid, signo); +#endif + +  return (INTERNAL_SYSCALL_ERROR_P (val, err) +	  ? INTERNAL_SYSCALL_ERRNO (val, err) : 0); +} +strong_alias (__pthread_kill, pthread_kill) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c new file mode 100644 index 000000000..804bfab44 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c @@ -0,0 +1,14 @@ +#include <pthreadP.h> + +#define LLL_MUTEX_LOCK(mutex) \ +  lll_cond_lock ((mutex)->__data.__lock, PTHREAD_MUTEX_PSHARED (mutex)) +#define LLL_MUTEX_TRYLOCK(mutex) \ +  lll_cond_trylock ((mutex)->__data.__lock) +#define LLL_ROBUST_MUTEX_LOCK(mutex, id) \ +  lll_robust_cond_lock ((mutex)->__data.__lock, id, \ +			PTHREAD_ROBUST_MUTEX_PSHARED (mutex)) +#define __pthread_mutex_lock __pthread_mutex_cond_lock +#define __pthread_mutex_lock_full __pthread_mutex_cond_lock_full +#define NO_INCR + +#include <pthread_mutex_lock.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_setaffinity.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_setaffinity.c new file mode 100644 index 000000000..467e8ec70 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_setaffinity.c @@ -0,0 +1,91 @@ +/* Copyright (C) 2003, 2004, 2006, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <alloca.h> +#include <errno.h> +#include <pthreadP.h> +#include <sysdep.h> +#include <sys/types.h> + + +size_t __kernel_cpumask_size attribute_hidden; + + +/* Determine the current affinity.  As a side affect we learn +   about the size of the cpumask_t in the kernel.  */ +extern int __determine_cpumask_size (pid_t tid); +libpthread_hidden_proto(__determine_cpumask_size) +int __determine_cpumask_size (pid_t tid) +{ +  INTERNAL_SYSCALL_DECL (err); +  int res; + +  size_t psize = 128; +  void *p = alloca (psize); + +  while (res = INTERNAL_SYSCALL (sched_getaffinity, err, 3, tid, psize, p), +	 INTERNAL_SYSCALL_ERROR_P (res, err) +	 && INTERNAL_SYSCALL_ERRNO (res, err) == EINVAL) +    p = extend_alloca (p, psize, 2 * psize); + +  if (res == 0 || INTERNAL_SYSCALL_ERROR_P (res, err)) +    return INTERNAL_SYSCALL_ERRNO (res, err); + +  __kernel_cpumask_size = res; + +  return 0; +} +libpthread_hidden_def(__determine_cpumask_size) + +int +pthread_setaffinity_np (pthread_t th, size_t cpusetsize, +			   const cpu_set_t *cpuset) +{ +  const struct pthread *pd = (const struct pthread *) th; + +  INTERNAL_SYSCALL_DECL (err); +  int res; + +  if (__builtin_expect (__kernel_cpumask_size == 0, 0)) +    { +      res = __determine_cpumask_size (pd->tid); +      if (res != 0) +	return res; +    } + +  /* We now know the size of the kernel cpumask_t.  Make sure the user +     does not request to set a bit beyond that.  */ +  for (size_t cnt = __kernel_cpumask_size; cnt < cpusetsize; ++cnt) +    if (((char *) cpuset)[cnt] != '\0') +      /* Found a nonzero byte.  This means the user request cannot be +	 fulfilled.  */ +      return EINVAL; + +  res = INTERNAL_SYSCALL (sched_setaffinity, err, 3, pd->tid, cpusetsize, +			  cpuset); + +#ifdef RESET_VGETCPU_CACHE +  if (!INTERNAL_SYSCALL_ERROR_P (res, err)) +    RESET_VGETCPU_CACHE (); +#endif + +  return (INTERNAL_SYSCALL_ERROR_P (res, err) +	  ? INTERNAL_SYSCALL_ERRNO (res, err) +	  : 0); +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_sigqueue.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_sigqueue.c new file mode 100644 index 000000000..9e49085ce --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_sigqueue.c @@ -0,0 +1,83 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2009. + +   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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include <signal.h> +#include <string.h> +#include <unistd.h> +#include <pthreadP.h> +#include <tls.h> +#include <sysdep.h> +#include <bits/kernel-features.h> + + +int +pthread_sigqueue ( +     pthread_t threadid, +     int signo, +     const union sigval value) +{ +#ifdef __NR_rt_tgsigqueueinfo +  struct pthread *pd = (struct pthread *) threadid; + +  /* Make sure the descriptor is valid.  */ +  if (DEBUGGING_P && INVALID_TD_P (pd)) +    /* Not a valid thread handle.  */ +    return ESRCH; + +  /* Force load of pd->tid into local variable or register.  Otherwise +     if a thread exits between ESRCH test and tgkill, we might return +     EINVAL, because pd->tid would be cleared by the kernel.  */ +  pid_t tid = atomic_forced_read (pd->tid); +  if (__builtin_expect (tid <= 0, 0)) +    /* Not a valid thread handle.  */ +    return ESRCH; + +  /* Disallow sending the signal we use for cancellation, timers, for +     for the setxid implementation.  */ +  if (signo == SIGCANCEL || signo == SIGTIMER || signo == SIGSETXID) +    return EINVAL; + +  /* Set up the siginfo_t structure.  */ +  siginfo_t info; +  memset (&info, '\0', sizeof (siginfo_t)); +  info.si_signo = signo; +  info.si_code = SI_QUEUE; +  info.si_pid = THREAD_GETMEM (THREAD_SELF, pid); +  info.si_uid = getuid (); +  info.si_value = value; + +  /* We have a special syscall to do the work.  */ +  INTERNAL_SYSCALL_DECL (err); + +  /* One comment: The PID field in the TCB can temporarily be changed +     (in fork).  But this must not affect this code here.  Since this +     function would have to be called while the thread is executing +     fork, it would have to happen in a signal handler.  But this is +     no allowed, pthread_sigqueue is not guaranteed to be async-safe.  */ +  int val = INTERNAL_SYSCALL (rt_tgsigqueueinfo, err, 4, +			      THREAD_GETMEM (THREAD_SELF, pid), +			      tid, signo, &info); + +  return (INTERNAL_SYSCALL_ERROR_P (val, err) +	  ? INTERNAL_SYSCALL_ERRNO (val, err) : 0); +#else +  return ENOSYS; +#endif +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_yield.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_yield.c new file mode 100644 index 000000000..5aecffcf0 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_yield.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <pthread.h> +#include <sched.h> + + +/* With the 1-on-1 model we implement this function is equivalent to +   the 'sched_yield' function.  */ +int +pthread_yield (void) +{ +  return sched_yield (); +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/raise.c b/libpthread/nptl/sysdeps/unix/sysv/linux/raise.c new file mode 100644 index 000000000..da35cfe9f --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/raise.c @@ -0,0 +1,74 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <sysdep.h> +#include <pthreadP.h> +#include <bits/kernel-features.h> + + +int +raise ( +     int sig) +{ +  struct pthread *pd = THREAD_SELF; +#if __ASSUME_TGKILL || defined __NR_tgkill +  pid_t pid = THREAD_GETMEM (pd, pid); +#endif +  pid_t selftid = THREAD_GETMEM (pd, tid); +  if (selftid == 0) +    { +      /* This system call is not supposed to fail.  */ +#ifdef INTERNAL_SYSCALL +      INTERNAL_SYSCALL_DECL (err); +      selftid = INTERNAL_SYSCALL (gettid, err, 0); +#else +      selftid = INLINE_SYSCALL (gettid, 0); +#endif +      THREAD_SETMEM (pd, tid, selftid); + +#if __ASSUME_TGKILL || defined __NR_tgkill +      /* We do not set the PID field in the TID here since we might be +	 called from a signal handler while the thread executes fork.  */ +      pid = selftid; +#endif +    } +#if __ASSUME_TGKILL || defined __NR_tgkill +  else +    /* raise is an async-safe function.  It could be called while the +       fork/vfork function temporarily invalidated the PID field.  Adjust for +       that.  */ +    if (__builtin_expect (pid <= 0, 0)) +      pid = (pid & INT_MAX) == 0 ? selftid : -pid; +#endif + +#if __ASSUME_TGKILL +  return INLINE_SYSCALL (tgkill, 3, pid, selftid, sig); +#else +# ifdef __NR_tgkill +  int res = INLINE_SYSCALL (tgkill, 3, pid, selftid, sig); +  if (res != -1 || errno != ENOSYS) +    return res; +# endif +  return INLINE_SYSCALL (tkill, 2, selftid, sig); +#endif +} +libc_hidden_def (raise) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/read.S b/libpthread/nptl/sysdeps/unix/sysv/linux/read.S new file mode 100644 index 000000000..d3adfa84c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/read.S @@ -0,0 +1,19 @@ +#include <sysdep-cancel.h> + +/* +extern int __read_nocancel (int, void *, size_t) attribute_hidden; +*/ +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +PSEUDO (__libc_read, read, 3) +ret +PSEUDO_END(__libc_read) + +libc_hidden_def (__read_nocancel) +libc_hidden_def (__libc_read) +weak_alias (__libc_read, __read) +libc_hidden_weak (__read) +weak_alias (__libc_read, read) +libc_hidden_weak (read) + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/recv.S b/libpthread/nptl/sysdeps/unix/sysv/linux/recv.S new file mode 100644 index 000000000..95fa6516e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/recv.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_recv +#error Missing definition of NR_recv needed for cancellation. +#endif +PSEUDO (__libc_recv, recv, 4) +ret +PSEUDO_END(__libc_recv) +libc_hidden_def (__libc_recv) +weak_alias (__libc_recv, __recv) +libc_hidden_weak (__recv) +weak_alias (__libc_recv, recv) +libc_hidden_weak (recv) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/recvfrom.S b/libpthread/nptl/sysdeps/unix/sysv/linux/recvfrom.S new file mode 100644 index 000000000..d9cc1e9b4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/recvfrom.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_recvfrom +#error Missing definition of NR_recvfrom needed for cancellation. +#endif +PSEUDO (__libc_recvfrom, recvfrom, 6) +ret +PSEUDO_END(__libc_recvfrom) +libc_hidden_def (__libc_recvfrom) +weak_alias (__libc_recvfrom, __recvfrom) +libc_hidden_weak (__recvfrom) +weak_alias (__libc_recvfrom, recvfrom) +libc_hidden_weak (recvfrom) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/recvmsg.S b/libpthread/nptl/sysdeps/unix/sysv/linux/recvmsg.S new file mode 100644 index 000000000..c761b907c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/recvmsg.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_recvmsg +#error Missing definition of NR_recvmsg needed for cancellation. +#endif +PSEUDO (__libc_recvmsg, recvmsg, 3) +ret +PSEUDO_END(__libc_recvmsg) +libc_hidden_def (__libc_recvmsg) +weak_alias (__libc_recvmsg, __recvmsg) +libc_hidden_weak (__recvmsg) +weak_alias (__libc_recvmsg, recvmsg) +libc_hidden_weak (recvmsg) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/register-atfork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/register-atfork.c new file mode 100644 index 000000000..f956ad565 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/register-atfork.c @@ -0,0 +1,149 @@ +/* Copyright (C) 2002, 2003, 2005, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <fork.h> +#include <atomic.h> +#include <tls.h> + + +/* Lock to protect allocation and deallocation of fork handlers.  */ +int __fork_lock = LLL_LOCK_INITIALIZER; + + +/* Number of pre-allocated handler entries.  */ +#define NHANDLER 48 + +/* Memory pool for fork handler structures.  */ +static struct fork_handler_pool +{ +  struct fork_handler_pool *next; +  struct fork_handler mem[NHANDLER]; +} fork_handler_pool; + + +static struct fork_handler * +fork_handler_alloc (void) +{ +  struct fork_handler_pool *runp = &fork_handler_pool; +  struct fork_handler *result = NULL; +  unsigned int i; + +  do +    { +      /* Search for an empty entry.  */ +      for (i = 0; i < NHANDLER; ++i) +	if (runp->mem[i].refcntr == 0) +	  goto found; +    } +  while ((runp = runp->next) != NULL); + +  /* We have to allocate a new entry.  */ +  runp = (struct fork_handler_pool *) calloc (1, sizeof (*runp)); +  if (runp != NULL) +    { +      /* Enqueue the new memory pool into the list.  */ +      runp->next = fork_handler_pool.next; +      fork_handler_pool.next = runp; + +      /* We use the last entry on the page.  This means when we start +	 searching from the front the next time we will find the first +	 entry unused.  */ +      i = NHANDLER - 1; + +    found: +      result = &runp->mem[i]; +      result->refcntr = 1; +      result->need_signal = 0; +    } + +  return result; +} + + +int +__register_atfork ( +     void (*prepare) (void), +     void (*parent) (void), +     void (*child) (void), +     void *dso_handle) +{ +  /* Get the lock to not conflict with other allocations.  */ +  lll_lock (__fork_lock, LLL_PRIVATE); + +  struct fork_handler *newp = fork_handler_alloc (); + +  if (newp != NULL) +    { +      /* Initialize the new record.  */ +      newp->prepare_handler = prepare; +      newp->parent_handler = parent; +      newp->child_handler = child; +      newp->dso_handle = dso_handle; + +      __linkin_atfork (newp); +    } + +  /* Release the lock.  */ +  lll_unlock (__fork_lock, LLL_PRIVATE); + +  return newp == NULL ? ENOMEM : 0; +} +libc_hidden_def (__register_atfork) + + +void +attribute_hidden +__linkin_atfork (struct fork_handler *newp) +{ +  do +    newp->next = __fork_handlers; +  while (catomic_compare_and_exchange_bool_acq (&__fork_handlers, +						newp, newp->next) != 0); +} + +#if 0 +libc_freeres_fn (free_mem) +{ +  /* Get the lock to not conflict with running forks.  */ +  lll_lock (__fork_lock, LLL_PRIVATE); + +  /* No more fork handlers.  */ +  __fork_handlers = NULL; + +  /* Free eventually alloated memory blocks for the object pool.  */ +  struct fork_handler_pool *runp = fork_handler_pool.next; + +  memset (&fork_handler_pool, '\0', sizeof (fork_handler_pool)); + +  /* Release the lock.  */ +  lll_unlock (__fork_lock, LLL_PRIVATE); + +  /* We can free the memory after releasing the lock.  */ +  while (runp != NULL) +    { +      struct fork_handler_pool *oldp = runp; +      runp = runp->next; +      free (oldp); +    } +} +#endif + diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sem_post.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_post.c new file mode 100644 index 000000000..edb97c4ba --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_post.c @@ -0,0 +1,58 @@ +/* sem_post -- post to a POSIX semaphore.  Generic futex-using version. +   Copyright (C) 2003, 2004, 2007, 2008 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <internaltypes.h> +#include <semaphore.h> +#include <tls.h> + +int +__new_sem_post (sem_t *sem) +{ +  struct new_sem *isem = (struct new_sem *) sem; + +  __typeof (isem->value) cur; +  do +    { +      cur = isem->value; +      if (isem->value == SEM_VALUE_MAX) +	{ +	  __set_errno (EOVERFLOW); +	  return -1; +	} +    } +  while (atomic_compare_and_exchange_bool_acq (&isem->value, cur + 1, cur)); + +  atomic_full_barrier (); +  if (isem->nwaiters > 0) +    { +      int err = lll_futex_wake (&isem->value, 1, +				isem->private ^ FUTEX_PRIVATE_FLAG); +      if (__builtin_expect (err, 0) < 0) +	{ +	  __set_errno (-err); +	  return -1; +	} +    } +  return 0; +} +weak_alias(__new_sem_post, sem_post) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c new file mode 100644 index 000000000..3e5e6dcae --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c @@ -0,0 +1,111 @@ +/* sem_timedwait -- wait on a semaphore.  Generic futex-using version. +   Copyright (C) 2003, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <internaltypes.h> +#include <semaphore.h> + +#include <pthreadP.h> + + +extern void __sem_wait_cleanup (void *arg) attribute_hidden; + + +int +sem_timedwait (sem_t *sem, const struct timespec *abstime) +{ +  struct new_sem *isem = (struct new_sem *) sem; +  int err; + +  if (atomic_decrement_if_positive (&isem->value) > 0) +    return 0; + +  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) +    { +      __set_errno (EINVAL); +      return -1; +    } + +  atomic_increment (&isem->nwaiters); + +  pthread_cleanup_push (__sem_wait_cleanup, isem); + +  while (1) +    { +      struct timeval tv; +      struct timespec rt; +      int sec, nsec; + +      /* Get the current time.  */ +      __gettimeofday (&tv, NULL); + +      /* Compute relative timeout.  */ +      sec = abstime->tv_sec - tv.tv_sec; +      nsec = abstime->tv_nsec - tv.tv_usec * 1000; +      if (nsec < 0) +	{ +	  nsec += 1000000000; +	  --sec; +	} + +      /* Already timed out?  */ +      err = -ETIMEDOUT; +      if (sec < 0) +	{ +	  __set_errno (ETIMEDOUT); +	  err = -1; +	  break; +	} + +      /* Do wait.  */ +      rt.tv_sec = sec; +      rt.tv_nsec = nsec; + +      /* Enable asynchronous cancellation.  Required by the standard.  */ +      int oldtype = __pthread_enable_asynccancel (); + +      err = lll_futex_timed_wait (&isem->value, 0, &rt, +				  isem->private ^ FUTEX_PRIVATE_FLAG); + +      /* Disable asynchronous cancellation.  */ +      __pthread_disable_asynccancel (oldtype); + +      if (err != 0 && err != -EWOULDBLOCK) +	{ +	  __set_errno (-err); +	  err = -1; +	  break; +	} + +      if (atomic_decrement_if_positive (&isem->value) > 0) +	{ +	  err = 0; +	  break; +	} +    } + +  pthread_cleanup_pop (0); + +  atomic_decrement (&isem->nwaiters); + +  return err; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sem_trywait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_trywait.c new file mode 100644 index 000000000..3cf1d9a8a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_trywait.c @@ -0,0 +1,44 @@ +/* sem_trywait -- wait on a semaphore.  Generic futex-using version. +   Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <internaltypes.h> +#include <semaphore.h> + + +int +__new_sem_trywait (sem_t *sem) +{ +  int *futex = (int *) sem; +  int val; + +  if (*futex > 0) +    { +      val = atomic_decrement_if_positive (futex); +      if (val > 0) +	return 0; +    } + +  __set_errno (EAGAIN); +  return -1; +} +weak_alias(__new_sem_trywait, sem_trywait) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sem_wait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_wait.c new file mode 100644 index 000000000..e661e09c8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_wait.c @@ -0,0 +1,84 @@ +/* sem_wait -- wait on a semaphore.  Generic futex-using version. +   Copyright (C) 2003, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <internaltypes.h> +#include <semaphore.h> + +#include <pthreadP.h> + + +void +attribute_hidden +__sem_wait_cleanup (void *arg) +{ +  struct new_sem *isem = (struct new_sem *) arg; + +  atomic_decrement (&isem->nwaiters); +} + + +int +__new_sem_wait (sem_t *sem) +{ +  struct new_sem *isem = (struct new_sem *) sem; +  int err; + +  if (atomic_decrement_if_positive (&isem->value) > 0) +    return 0; + +  atomic_increment (&isem->nwaiters); + +  pthread_cleanup_push (__sem_wait_cleanup, isem); + +  while (1) +    { +      /* Enable asynchronous cancellation.  Required by the standard.  */ +      int oldtype = __pthread_enable_asynccancel (); + +      err = lll_futex_wait (&isem->value, 0, +			    isem->private ^ FUTEX_PRIVATE_FLAG); + +      /* Disable asynchronous cancellation.  */ +      __pthread_disable_asynccancel (oldtype); + +      if (err != 0 && err != -EWOULDBLOCK) +	{ +	  __set_errno (-err); +	  err = -1; +	  break; +	} + +      if (atomic_decrement_if_positive (&isem->value) > 0) +	{ +	  err = 0; +	  break; +	} +    } + +  pthread_cleanup_pop (0); + +  atomic_decrement (&isem->nwaiters); + +  return err; +} +weak_alias(__new_sem_wait, sem_wait) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/send.S b/libpthread/nptl/sysdeps/unix/sysv/linux/send.S new file mode 100644 index 000000000..eb744c712 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/send.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_send +#error Missing definition of NR_send needed for cancellation. +#endif +PSEUDO (__libc_send, send, 4) +ret +PSEUDO_END (__libc_send) +libc_hidden_def (__libc_send) +weak_alias (__libc_send, __send) +libc_hidden_weak (__send) +weak_alias (__libc_send, send) +libc_hidden_weak (send) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sendmsg.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sendmsg.S new file mode 100644 index 000000000..4c41e01c1 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sendmsg.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_sendmsg +#error Missing definition of NR_sendmsg needed for cancellation. +#endif +PSEUDO (__libc_sendmsg, sendmsg, 3) +ret +PSEUDO_END(__libc_sendmsg) +libc_hidden_def (__libc_sendmsg) +weak_alias (__libc_sendmsg, __sendmsg) +libc_hidden_weak (__sendmsg) +weak_alias (__libc_sendmsg, sendmsg) +libc_hidden_weak (sendmsg) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sendto.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sendto.S new file mode 100644 index 000000000..7cb5278e9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sendto.S @@ -0,0 +1,12 @@ +#include <sysdep-cancel.h> +#ifndef __NR_sendto +#error Missing definition of NR_sendto needed for cancellation. +#endif +PSEUDO (__libc_sendto, sendto, 6) +ret +PSEUDO_END(__libc_sendto) +libc_hidden_def (__libc_sendto) +weak_alias (__libc_sendto, __sendto) +libc_hidden_weak (__sendto) +weak_alias (__libc_sendto, sendto) +libc_hidden_weak (sendto) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/Makefile new file mode 100644 index 000000000..43a6fad84 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../../../../ +top_builddir=../../../../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.arch +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/Makefile.arch new file mode 100644 index 000000000..940bd62f8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/Makefile.arch @@ -0,0 +1,85 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_SSRC = pt-vfork.S pthread_once.S pthread_rwlock_wrlock.S \ +			pthread_rwlock_rdlock.S pthread_rwlock_unlock.S \ +			lowlevellock.S lowlevelrobustlock.S pthread_barrier_wait.S \ +			pthread_cond_broadcast.S pthread_cond_signal.S \ +			pthread_rwlock_timedwrlock.S pthread_rwlock_timedrdlock.S \ +			sem_post.S sem_timedwait.S sem_trywait.S sem_wait.S + +libc_a_CSRC = fork.c +libc_a_SSRC = libc-lowlevellock.S clone.S vfork.S + +ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y) +CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__ +endif + +ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_once.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_rwlock_wrlock.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_rwlock_rdlock.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_rwlock_unlock.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_rwlock_unlock.S = -D_LIBC_REENTRANT -DUSE___THREAD + +ASFLAGS-pthread_barrier_wait.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_cond_broadcast.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_cond_signal.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_cond_wait.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_cond_timedwait.S = -D_LIBC_REENTRANT -DUSE___THREAD + +ASFLAGS-pthread_rwlock_timedwrlock.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_rwlock_timedrdlock.S = -D_LIBC_REENTRANT -DUSE___THREAD + +ASFLAGS-sem_post.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-sem_timedwait.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-sem_trywait.S = -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-sem_wait.S = -D_LIBC_REENTRANT -DUSE___THREAD + +ASFLAGS-libc-lowlevellock.S = -D_LIBC_REENTRANT  -DUSE___THREAD + +ASFLAGS-lowlevellock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-lowlevelrobustlock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD + +ASFLAGS-clone.S = -D_LIBC_REENTRANT +ASFLAGS-vfork.S = -D_LIBC_REENTRANT + +ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) +#Needed to use the correct SYSCALL_ERROR_HANDLER +ASFLAGS-clone.S += -DUSE___THREAD +ASFLAGS-vfork.S += -DUSE___THREAD +endif + +CFLAGS += $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/sh +LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/sh + +LINUX_ARCH_OBJ:=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libpthread_SSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(LINUX_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(LINUX_ARCH_OBJ) +endif +libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y+=$(LINUX_ARCH_OBJS) + +LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC)) +LIBC_LINUX_ARCH_OBJ+=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libc_a_SSRC)) + +libc-static-y+=$(LIBC_LINUX_ARCH_OBJ) +libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS) + +libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ) + +objclean-y+=nptl_linux_arch_clean + +nptl_linux_arch_clean: +	$(do_rm) $(addprefix $(LINUX_ARCH_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h new file mode 100644 index 000000000..badcda570 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h @@ -0,0 +1,183 @@ +/* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 +   Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H	1 + +#include <endian.h> + +#define __SIZEOF_PTHREAD_ATTR_T 36 +#define __SIZEOF_PTHREAD_MUTEX_T 24 +#define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +#define __SIZEOF_PTHREAD_COND_T 48 +#define __SIZEOF_PTHREAD_COND_COMPAT_T 12 +#define __SIZEOF_PTHREAD_CONDATTR_T 4 +#define __SIZEOF_PTHREAD_RWLOCK_T 32 +#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +#define __SIZEOF_PTHREAD_BARRIER_T 20 +#define __SIZEOF_PTHREAD_BARRIERATTR_T 4 + + +/* Thread identifiers.  The structure of the attribute type is not +   exposed on purpose.  */ +typedef unsigned long int pthread_t; + + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_ATTR_T]; +  long int __align; +} pthread_attr_t; + + +typedef struct __pthread_internal_slist +{ +  struct __pthread_internal_slist *__next; +} __pthread_slist_t; + + +/* Data structures for mutex handling.  The structure of the attribute +   type is not exposed on purpose.  */ +typedef union +{ +  struct __pthread_mutex_s +  { +    int __lock; +    unsigned int __count; +    int __owner; +    /* KIND must stay at this position in the structure to maintain +       binary compatibility.  */ +    int __kind; +    unsigned int __nusers; +    __extension__ union +    { +      int __spins; +      __pthread_slist_t __list; +    }; +  } __data; +  char __size[__SIZEOF_PTHREAD_MUTEX_T]; +  long int __align; +} pthread_mutex_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; +  long int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling.  The structure of +   the attribute type is not exposed on purpose.  */ +typedef union +{ +  struct +  { +    int __lock; +    unsigned int __futex; +    __extension__ unsigned long long int __total_seq; +    __extension__ unsigned long long int __wakeup_seq; +    __extension__ unsigned long long int __woken_seq; +    void *__mutex; +    unsigned int __nwaiters; +    unsigned int __broadcast_seq; +  } __data; +  char __size[__SIZEOF_PTHREAD_COND_T]; +  __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_CONDATTR_T]; +  long int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling.  The +   structure of the attribute type is not exposed on purpose.  */ +typedef union +{ +  struct +  { +    int __lock; +    unsigned int __nr_readers; +    unsigned int __readers_wakeup; +    unsigned int __writer_wakeup; +    unsigned int __nr_readers_queued; +    unsigned int __nr_writers_queued; +#if __BYTE_ORDER == __BIG_ENDIAN +    unsigned char __pad1; +    unsigned char __pad2; +    unsigned char __shared; +    /* FLAGS must stay at this position in the structure to maintain +       binary compatibility.  */ +    unsigned char __flags; +#else +    /* FLAGS must stay at this position in the structure to maintain +       binary compatibility.  */ +    unsigned char __flags; +    unsigned char __shared; +    unsigned char __pad1; +    unsigned char __pad2; +#endif +    pthread_t __writer; +  } __data; +  char __size[__SIZEOF_PTHREAD_RWLOCK_T]; +  long int __align; +} pthread_rwlock_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; +  long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type.  */ +typedef volatile int pthread_spinlock_t; + + +/* POSIX barriers data type.  The structure of the type is +   deliberately not exposed.  */ +typedef union +{ +  char __size[__SIZEOF_PTHREAD_BARRIER_T]; +  long int __align; +} pthread_barrier_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; +  int __align; +} pthread_barrierattr_t; +#endif + + +#endif	/* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/semaphore.h new file mode 100644 index 000000000..934493c30 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/semaphore.h @@ -0,0 +1,36 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + + +#define __SIZEOF_SEM_T	16 + + +/* Value returned if `sem_open' failed.  */ +#define SEM_FAILED      ((sem_t *) 0) + + +typedef union +{ +  char __size[__SIZEOF_SEM_T]; +  long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/clone.S new file mode 100644 index 000000000..918d57926 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/clone.S @@ -0,0 +1,2 @@ +#define RESET_PID +#include <libc/sysdeps/linux/sh/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/createthread.c new file mode 100644 index 000000000..e17c0174b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/createthread.c @@ -0,0 +1,24 @@ +/* Copyright (C) 2003 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +/* Value passed to 'clone' for initialization of the thread register.  */ +#define TLS_VALUE (pd + 1) + + +/* Get the real implementation.  */ +#include <sysdeps/pthread/createthread.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/fork.c new file mode 100644 index 000000000..6868b9bcd --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/fork.c @@ -0,0 +1,30 @@ +/* Copyright (C) 2003 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sched.h> +#include <signal.h> +#include <sysdep.h> +#include <tls.h> + +/* TLS pointer argument is passed as the 5-th argument.  */ +#define ARCH_FORK() \ +  INLINE_SYSCALL (clone, 5,						      \ +		  CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0,     \ +		  NULL, &THREAD_SELF->tid, NULL) + +#include "../fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/libc-lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/libc-lowlevellock.S new file mode 100644 index 000000000..feb82110c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/libc-lowlevellock.S @@ -0,0 +1,19 @@ +/* Copyright (C) 2003, 2007 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "lowlevellock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevel-atomic.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevel-atomic.h new file mode 100644 index 000000000..c7028360f --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevel-atomic.h @@ -0,0 +1,81 @@ +/* Copyright (C) 2003, 2004, 2008 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifdef __ASSEMBLER__ + +#define _IMP1 #1 +#define _IMM1 #-1 +#define _IMM4 #-4 +#define _IMM6 #-6 +#define _IMM8 #-8 + +#define	INC(mem, reg) \ +	.align	2; \ +	mova	99f, r0; \ +	mov	r15, r1; \ +	mov	_IMM6, r15; \ +98:	mov.l	mem, reg; \ +	add	_IMP1, reg; \ +	mov.l	reg, mem; \ +99:	mov	r1, r15 + +#define	DEC(mem, reg) \ +	.align	2; \ +	mova	99f, r0; \ +	mov	r15, r1; \ +	mov	_IMM6, r15; \ +98:	mov.l	mem, reg; \ +	add	_IMM1, reg; \ +	mov.l	reg, mem; \ +99:	mov	r1, r15 + +#define	XADD(reg, mem, old, tmp) \ +	.align	2; \ +	mova	99f, r0; \ +	nop; \ +	mov	r15, r1; \ +	mov	_IMM8, r15; \ +98:	mov.l	mem, old; \ +	mov	reg, tmp; \ +	add	old, tmp; \ +	mov.l	tmp, mem; \ +99:	mov	r1, r15 + +#define	XCHG(reg, mem, old) \ +	.align	2; \ +	mova	99f, r0; \ +	nop; \ +	mov	r15, r1; \ +	mov	_IMM4, r15; \ +98:	mov.l	mem, old; \ +	mov.l	reg, mem; \ +99:	mov	r1, r15 + +#define	CMPXCHG(reg, mem, new, old) \ +	.align	2; \ +	mova	99f, r0; \ +	nop; \ +	mov	r15, r1; \ +	mov	_IMM8, r15; \ +98:	mov.l	mem, old; \ +	cmp/eq	old, reg; \ +	bf	99f; \ +	mov.l	new, mem; \ +99:	mov	r1, r15 + +#endif  /* __ASSEMBLER__ */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.S new file mode 100644 index 000000000..00edc75a7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.S @@ -0,0 +1,540 @@ +/* Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 +   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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <bits/kernel-features.h> +#include <lowlevellock.h> +#include <tcb-offsets.h> +#include "lowlevel-atomic.h" + +	.text + +#ifdef __ASSUME_PRIVATE_FUTEX +# define LOAD_PRIVATE_FUTEX_WAIT(reg,tmp,tmp2) \ +	mov	#(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg; \ +	extu.b	reg, reg +# define LOAD_PRIVATE_FUTEX_WAKE(reg,tmp,tmp2) \ +	mov	#(FUTEX_WAKE | FUTEX_PRIVATE_FLAG), reg; \ +	extu.b	reg, reg +# define LOAD_FUTEX_WAIT(reg,tmp,tmp2) \ +	mov	#(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), tmp; \ +	extu.b	tmp, tmp; \ +	xor	tmp, reg +# define LOAD_FUTEX_WAIT_ABS(reg,tmp,tmp2) \ +	mov	#(FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG), tmp; \ +	extu.b	tmp, tmp; \ +	mov	#(FUTEX_CLOCK_REALTIME >> 8), tmp2; \ +	swap.b	tmp2, tmp2; \ +	or	tmp2, tmp; \ +	xor	tmp, reg +# define LOAD_FUTEX_WAKE(reg,tmp,tmp2) \ +	mov	#(FUTEX_WAKE | FUTEX_PRIVATE_FLAG), tmp; \ +	extu.b	tmp, tmp; \ +	xor	tmp, reg +#else +# if FUTEX_WAIT == 0 +#  define LOAD_PRIVATE_FUTEX_WAIT(reg,tmp,tmp2) \ +	stc	gbr, tmp	; \ +	mov.w	99f, reg	; \ +	add	reg, tmp	; \ +	bra	98f		; \ +	 mov.l	@tmp, reg	; \ +99:	.word	PRIVATE_FUTEX - TLS_PRE_TCB_SIZE ; \ +98: +# else +#  define LOAD_PRIVATE_FUTEX_WAIT(reg,tmp,tmp2) \ +	stc	gbr, tmp	; \ +	mov.w	99f, reg	; \ +	add	reg, tmp	; \ +	mov.l	@tmp, reg	; \ +	bra	98f		; \ +	 mov	#FUTEX_WAIT, tmp ; \ +99:	.word	PRIVATE_FUTEX - TLS_PRE_TCB_SIZE ; \ +98:	or	tmp, reg +# endif +# define LOAD_PRIVATE_FUTEX_WAKE(reg,tmp,tmp2) \ +	stc	gbr, tmp	; \ +	mov.w	99f, reg	; \ +	add	reg, tmp	; \ +	mov.l	@tmp, reg	; \ +	bra	98f		; \ +	 mov	#FUTEX_WAKE, tmp ; \ +99:	.word	PRIVATE_FUTEX - TLS_PRE_TCB_SIZE ; \ +98:	or	tmp, reg +# if FUTEX_WAIT == 0 +#  define LOAD_FUTEX_WAIT(reg,tmp,tmp2) \ +	stc	gbr, tmp	; \ +	mov.w	99f, tmp2	; \ +	add	tmp2, tmp	; \ +	mov.l	@tmp, tmp2	; \ +	bra	98f		; \ +	 mov	#FUTEX_PRIVATE_FLAG, tmp ; \ +99:	.word	PRIVATE_FUTEX - TLS_PRE_TCB_SIZE ; \ +98:	extu.b	tmp, tmp	; \ +	xor	tmp, reg	; \ +	and	tmp2, reg +# else +#  define LOAD_FUTEX_WAIT(reg,tmp,tmp2) \ +	stc	gbr, tmp	; \ +	mov.w	99f, tmp2	; \ +	add	tmp2, tmp	; \ +	mov.l	@tmp, tmp2	; \ +	bra	98f		; \ +	 mov	#FUTEX_PRIVATE_FLAG, tmp ; \ +99:	.word	PRIVATE_FUTEX - TLS_PRE_TCB_SIZE ; \ +98:	extu.b	tmp, tmp	; \ +	xor	tmp, reg	; \ +	and	tmp2, reg	; \ +	mov	#FUTEX_WAIT, tmp ; \ +	or	tmp, reg +# endif +# define LOAD_FUTEX_WAIT_ABS(reg,tmp,tmp2) \ +	stc	gbr, tmp	; \ +	mov.w	99f, tmp2	; \ +	add	tmp2, tmp	; \ +	mov.l	@tmp, tmp2	; \ +	bra	98f		; \ +	 mov	#FUTEX_PRIVATE_FLAG, tmp ; \ +99:	.word	PRIVATE_FUTEX - TLS_PRE_TCB_SIZE ; \ +98:	extu.b	tmp, tmp	; \ +	xor	tmp, reg	; \ +	and	tmp2, reg	; \ +	mov	#FUTEX_WAIT_BITSET, tmp ; \ +	mov	#(FUTEX_CLOCK_REALTIME >> 8), tmp2; \ +	swap.b	tmp2, tmp2; \ +	or	tmp2, tmp; \ +	or	tmp, reg +# define LOAD_FUTEX_WAKE(reg,tmp,tmp2) \ +	stc	gbr, tmp	; \ +	mov.w	99f, tmp2	; \ +	add	tmp2, tmp	; \ +	mov.l	@tmp, tmp2	; \ +	bra	98f		; \ +	 mov	#FUTEX_PRIVATE_FLAG, tmp ; \ +99:	.word	PRIVATE_FUTEX - TLS_PRE_TCB_SIZE ; \ +98:	extu.b	tmp, tmp	; \ +	xor	tmp, reg	; \ +	and	tmp2, reg	; \ +	mov	#FUTEX_WAKE, tmp ; \ +	or	tmp, reg +#endif + +	.globl	__lll_lock_wait_private +	.type	__lll_lock_wait_private,@function +	.hidden	__lll_lock_wait_private +	.align	5 +	cfi_startproc +__lll_lock_wait_private: +	mov.l	r8, @-r15 +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset (r8, 0) +	mov	r4, r6 +	mov	r5, r8 +	mov	#0, r7		/* No timeout.  */ +	LOAD_PRIVATE_FUTEX_WAIT (r5, r0, r1) + +	mov	#2, r4 +	cmp/eq	r4, r6 +	bf	2f + +1: +	mov	r8, r4 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD + +2: +	mov	#2, r6 +	XCHG (r6, @r8, r2) +	tst	r2, r2 +	bf	1b + +	mov.l	@r15+, r8 +	rts +	 mov	r2, r0 +	cfi_endproc +	.size	__lll_lock_wait_private,.-__lll_lock_wait_private + +#ifdef NOT_IN_libc +	.globl	__lll_lock_wait +	.type	__lll_lock_wait,@function +	.hidden	__lll_lock_wait +	.align	5 +	cfi_startproc +__lll_lock_wait: +	mov.l	r9, @-r15 +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset (r9, 0) +	mov.l	r8, @-r15 +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset (r8, 0) +	mov	r6, r9 +	mov	r4, r6 +	mov	r5, r8 +	mov	#0, r7		/* No timeout.  */ +	mov	r9, r5 +	LOAD_FUTEX_WAIT (r5, r0, r1) + +	mov	#2, r4 +	cmp/eq	r4, r6 +	bf	2f + +1: +	mov	r8, r4 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD + +2: +	mov	#2, r6 +	XCHG (r6, @r8, r2) +	tst	r2, r2 +	bf	1b + +	mov.l	@r15+, r8 +	mov.l	@r15+, r9 +	ret +	 mov	r2, r0 +	cfi_endproc +	.size	__lll_lock_wait,.-__lll_lock_wait + +	/*      r5  (r8): futex +		r7 (r11): flags +		r6  (r9): timeout +		r4 (r10): futex value +	*/ +	.globl	__lll_timedlock_wait +	.type	__lll_timedlock_wait,@function +	.hidden	__lll_timedlock_wait +	.align	5 +	cfi_startproc +__lll_timedlock_wait: +	mov.l	r12, @-r15 +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset (r12, 0) + +# ifndef __ASSUME_FUTEX_CLOCK_REALTIME +	mov.l	.Lhave, r1 +#  ifdef __PIC__ +	mova	.Lgot, r0 +	mov.l	.Lgot, r12 +	add	r0, r12 +	add	r12, r1 +#  endif +	mov.l	@r1, r0 +	tst	r0, r0 +	bt	.Lreltmo +# endif + +	mov	r4, r2 +	mov	r5, r4 +	mov	r7, r5 +	mov	r6, r7 +	LOAD_FUTEX_WAIT_ABS (r5, r0, r1) + +	mov	#2, r6 +	cmp/eq	r6, r2 +	bf/s	2f +	 mov	r6, r2 + +1: +	mov	#2, r6 +	mov	#-1, r1 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x16 +	SYSCALL_INST_PAD +	mov	r0, r6 + +2: +	XCHG	(r2, @r4, r3)	/* NB:   lock is implied */ + +	tst	r3, r3 +	bt/s	3f +	 mov	r6, r0 + +	cmp/eq	#-ETIMEDOUT, r0 +	bt	4f +	cmp/eq	#-EINVAL, r0 +	bf	1b +4: +	neg	r0, r3 +3: +	mov	r3, r0 +	rts +	 mov.l	@r15+, r12 + +	.align	2 +# ifndef __ASSUME_FUTEX_CLOCK_REALTIME +# ifdef __PIC__ +.Lgot: +	.long	_GLOBAL_OFFSET_TABLE_ +.Lhave: +	.long	__have_futex_clock_realtime@GOTOFF +# else +.Lhave: +	.long	__have_futex_clock_realtime +# endif + +.Lreltmo: +	/* Check for a valid timeout value.  */ +	mov.l	@(4,r6), r1 +	mov.l	.L1g, r0 +	cmp/hs	r0, r1 +	bt	3f + +	mov.l	r11, @-r15 +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset (r11, 0) +	mov.l	r10, @-r15 +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset (r10, 0) +	mov.l	r9, @-r15 +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset (r9, 0) +	mov.l	r8, @-r15 +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset (r8, 0) +	mov	r7, r11 +	mov	r4, r10 +	mov	r6, r9 +	mov	r5, r8 + +	/* Stack frame for the timespec and timeval structs.  */ +	add	#-8, r15 +	cfi_adjust_cfa_offset(8) + +	mov	#2, r2 +	XCHG (r2, @r8, r3) + +	tst	r3, r3 +	bt	6f + +1: +	/* Get current time.  */ +	mov	r15, r4 +	mov	#0, r5 +	mov	#__NR_gettimeofday, r3 +	trapa	#0x12 +	SYSCALL_INST_PAD + +	/* Compute relative timeout.  */ +	mov.l	@(4,r15), r0 +	mov.w	.L1k, r1 +	dmulu.l	r0, r1		/* Micro seconds to nano seconds.  */ +	mov.l	@r9, r2 +	mov.l	@(4,r9), r3 +	mov.l	@r15, r0 +	sts	macl, r1 +	sub	r0, r2 +	clrt +	subc	r1, r3 +	bf	4f +	mov.l	.L1g, r1 +	add	r1, r3 +	add	#-1, r2 +4: +	cmp/pz	r2 +	bf	2f		/* Time is already up.  */ + +	mov.l	r2, @r15	/* Store relative timeout.  */ +	mov.l	r3, @(4,r15) + +	mov	r8, r4 +	mov	r11, r5 +	LOAD_FUTEX_WAIT (r5, r0, r1) +	mov	r10, r6 +	mov	r15, r7 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD +	mov	r0, r5 + +	mov	#2, r2 +	XCHG (r2, @r8, r3) + +	tst	r3, r3 +	bt/s	6f +	 mov	#-ETIMEDOUT, r1 +	cmp/eq	r5, r1 +	bf	1b + +2:	mov	#ETIMEDOUT, r3 + +6: +	mov	r3, r0 +	add	#8, r15 +	mov.l	@r15+, r8 +	mov.l	@r15+, r9 +	mov.l	@r15+, r10 +	mov.l	@r15+, r11 +	rts +	 mov.l	@r15+, r12 + +3: +	mov.l	@r15+, r12 +	rts +	 mov	#EINVAL, r0 +# endif +	cfi_endproc + +.L1k: +	.word	1000 +	.align	2 +.L1g: +	.long	1000000000 + +	.size	__lll_timedlock_wait,.-__lll_timedlock_wait +#endif + +	.globl	__lll_unlock_wake_private +	.type	__lll_unlock_wake_private,@function +	.hidden	__lll_unlock_wake_private +	.align	5 +	cfi_startproc +__lll_unlock_wake_private: +	LOAD_PRIVATE_FUTEX_WAKE (r5, r0, r1) +	mov	#1, r6		/* Wake one thread.  */ +	mov	#0, r7 +	mov.l	r7, @r4		/* Stores 0.  */ +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD +	rts +	 nop +	cfi_endproc +	.size	__lll_unlock_wake_private,.-__lll_unlock_wake_private + +#ifdef NOT_IN_libc +	.globl	__lll_unlock_wake +	.type	__lll_unlock_wake,@function +	.hidden	__lll_unlock_wake +	.align	5 +	cfi_startproc +__lll_unlock_wake: +	LOAD_FUTEX_WAKE (r5, r0, r1) +	mov	#1, r6		/* Wake one thread.  */ +	mov	#0, r7 +	mov.l	r7, @r4		/* Stores 0.  */ +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD +	rts +	 nop +	cfi_endproc +	.size	__lll_unlock_wake,.-__lll_unlock_wake + +	.globl	__lll_timedwait_tid +	.type	__lll_timedwait_tid,@function +	.hidden	__lll_timedwait_tid +	.align	5 +	cfi_startproc +__lll_timedwait_tid: +	mov.l	r9, @-r15 +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset (r9, 0) +	mov.l	r8, @-r15 +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset (r8, 0) +	mov	r4, r8 +	mov	r5, r9 + +	/* Stack frame for the timespec and timeval structs.  */ +	add	#-8, r15 +	cfi_adjust_cfa_offset(8) + +2: +	/* Get current time.  */ +	mov	r15, r4 +	mov	#0, r5 +	mov	#__NR_gettimeofday, r3 +	trapa	#0x12 +	SYSCALL_INST_PAD + +	/* Compute relative timeout.  */ +	mov.l	@(4,r15), r0 +	mov.w	.L1k2, r1 +	dmulu.l	r0, r1		/* Micro seconds to nano seconds.  */ +	mov.l	@r9, r2 +	mov.l	@(4,r9), r3 +	mov.l	@r15, r0 +	sts	macl, r1 +	sub	r0, r2 +	clrt +	subc	r1, r3 +	bf	5f +	mov.l	.L1g2, r1 +	add	r1, r3 +	add	#-1, r2 +5: +	cmp/pz	r2 +	bf	6f		/* Time is already up.  */ + +	mov.l	r2, @r15	/* Store relative timeout.  */ +	mov.l	r3, @(4,r15) + +	mov.l	@r8, r2 +	tst	r2, r2 +	bt	4f + +	mov	r8, r4 +	/* XXX The kernel so far uses global futex for the wakeup at +	   all times.  */ +	mov	#0, r5 +	extu.b	r5, r5 +	mov	r2, r6 +	mov	r15, r7 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD + +	mov.l	@r8, r2 +	tst	r2, r2 +	bf	1f +4: +	mov	#0, r0 +3: +	add	#8, r15 +	mov.l	@r15+, r8 +	rts +	 mov.l	@r15+, r9 +1: +	/* Check whether the time expired.  */ +	mov	#-ETIMEDOUT, r1 +	cmp/eq	r0, r1 +	bf	2b +6: +	bra	3b +	 mov	#ETIMEDOUT, r0 +	cfi_endproc + +.L1k2: +	.word	1000 +	.align	2 +.L1g2: +	.long	1000000000 +	.size	__lll_timedwait_tid,.-__lll_timedwait_tid +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.h new file mode 100644 index 000000000..19ce7fe40 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.h @@ -0,0 +1,420 @@ +/* Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009 +   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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H	1 + +#ifndef __ASSEMBLER__ +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> +#include <bits/kernel-features.h> +#endif + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 +#define FUTEX_CMP_REQUEUE	4 +#define FUTEX_WAKE_OP		5 +#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_PRIVATE_FLAG	128 +#define FUTEX_CLOCK_REALTIME	256 + +#define FUTEX_BITSET_MATCH_ANY	0xffffffff + +#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE	((4 << 24) | 1) + +/* 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 + +#ifndef __ASSEMBLER__ + +/* Initializer for compatibility lock.  */ +#define LLL_LOCK_INITIALIZER		(0) +#define LLL_LOCK_INITIALIZER_LOCKED	(1) +#define LLL_LOCK_INITIALIZER_WAITERS	(2) + +extern int __lll_lock_wait_private (int val, int *__futex) +  attribute_hidden; +extern int __lll_lock_wait (int val, int *__futex, int private) +  attribute_hidden; +extern int __lll_timedlock_wait (int val, int *__futex, +				 const struct timespec *abstime, int private) +  attribute_hidden; +extern int __lll_robust_lock_wait (int val, int *__futex, int private) +  attribute_hidden; +extern int __lll_robust_timedlock_wait (int val, int *__futex, +					const struct timespec *abstime, +					int private) +  attribute_hidden; +extern int __lll_unlock_wake_private (int *__futex) attribute_hidden; +extern int __lll_unlock_wake (int *__futex, int private) attribute_hidden; + +#define lll_trylock(futex) \ +  ({ unsigned char __result; \ +     __asm __volatile ("\ +	.align 2\n\ +	mova 1f,r0\n\ +	nop\n\ +	mov r15,r1\n\ +	mov #-8,r15\n\ +     0: mov.l @%1,r2\n\ +	cmp/eq r2,%3\n\ +	bf 1f\n\ +	mov.l %2,@%1\n\ +     1: mov r1,r15\n\ +	mov #-1,%0\n\ +	negc %0,%0"\ +	: "=r" (__result) \ +	: "r" (&(futex)), \ +	  "r" (LLL_LOCK_INITIALIZER_LOCKED), \ +	  "r" (LLL_LOCK_INITIALIZER) \ +	: "r0", "r1", "r2", "t", "memory"); \ +     __result; }) + +#define lll_robust_trylock(futex, id)	\ +  ({ unsigned char __result; \ +     __asm __volatile ("\ +	.align 2\n\ +	mova 1f,r0\n\ +	nop\n\ +	mov r15,r1\n\ +	mov #-8,r15\n\ +     0: mov.l @%1,r2\n\ +	cmp/eq r2,%3\n\ +	bf 1f\n\ +	mov.l %2,@%1\n\ +     1: mov r1,r15\n\ +	mov #-1,%0\n\ +	negc %0,%0"\ +	: "=r" (__result) \ +	: "r" (&(futex)), \ +	  "r" (id), \ +	  "r" (LLL_LOCK_INITIALIZER) \ +	: "r0", "r1", "r2", "t", "memory"); \ +     __result; }) + +#define lll_cond_trylock(futex) \ +  ({ unsigned char __result; \ +     __asm __volatile ("\ +	.align 2\n\ +	mova 1f,r0\n\ +	nop\n\ +	mov r15,r1\n\ +	mov #-8,r15\n\ +     0: mov.l @%1,r2\n\ +	cmp/eq r2,%3\n\ +	bf 1f\n\ +	mov.l %2,@%1\n\ +     1: mov r1,r15\n\ +	mov #-1,%0\n\ +	negc %0,%0"\ +	: "=r" (__result) \ +	: "r" (&(futex)), \ +	  "r" (LLL_LOCK_INITIALIZER_WAITERS), \ +	  "r" (LLL_LOCK_INITIALIZER) \ +	: "r0", "r1", "r2", "t", "memory"); \ +     __result; }) + +#define lll_lock(futex, private) \ +  (void) ({ int __result, *__futex = &(futex); \ +	    __asm __volatile ("\ +		.align 2\n\ +		mova 1f,r0\n\ +		nop\n\ +		mov r15,r1\n\ +		mov #-8,r15\n\ +	     0: mov.l @%2,%0\n\ +		tst %0,%0\n\ +		bf 1f\n\ +		mov.l %1,@%2\n\ +	     1: mov r1,r15"\ +		: "=&r" (__result) : "r" (1), "r" (__futex) \ +		: "r0", "r1", "t", "memory"); \ +	    if (__result) \ +	      { \ +		if (__builtin_constant_p (private) \ +		    && (private) == LLL_PRIVATE) \ +		  __lll_lock_wait_private (__result, __futex); \ +	        else \ +		  __lll_lock_wait (__result, __futex, (private));	\ +	      } \ +    }) + +#define lll_robust_lock(futex, id, private) \ +  ({ int __result, *__futex = &(futex); \ +     __asm __volatile ("\ +	.align 2\n\ +	mova 1f,r0\n\ +	nop\n\ +	mov r15,r1\n\ +	mov #-8,r15\n\ +      0: mov.l @%2,%0\n\ +	tst %0,%0\n\ +	bf 1f\n\ +	mov.l %1,@%2\n\ +      1: mov r1,r15"\ +	: "=&r" (__result) : "r" (id), "r" (__futex) \ +	: "r0", "r1", "t", "memory"); \ +     if (__result) \ +       __result = __lll_robust_lock_wait (__result, __futex, private); \ +     __result; }) + +/* Special version of lll_mutex_lock which causes the unlock function to +   always wakeup waiters.  */ +#define lll_cond_lock(futex, private) \ +  (void) ({ int __result, *__futex = &(futex); \ +	    __asm __volatile ("\ +		.align 2\n\ +		mova 1f,r0\n\ +		nop\n\ +		mov r15,r1\n\ +		mov #-8,r15\n\ +	     0: mov.l @%2,%0\n\ +		tst %0,%0\n\ +		bf 1f\n\ +		mov.l %1,@%2\n\ +	     1: mov r1,r15"\ +		: "=&r" (__result) : "r" (2), "r" (__futex) \ +		: "r0", "r1", "t", "memory"); \ +	    if (__result) \ +	      __lll_lock_wait (__result, __futex, private); }) + +#define lll_robust_cond_lock(futex, id, private) \ +  ({ int __result, *__futex = &(futex); \ +     __asm __volatile ("\ +	.align 2\n\ +	mova 1f,r0\n\ +	nop\n\ +	mov r15,r1\n\ +	mov #-8,r15\n\ +     0: mov.l @%2,%0\n\ +	tst %0,%0\n\ +	bf 1f\n\ +	mov.l %1,@%2\n\ +     1: mov r1,r15"\ +	: "=&r" (__result) : "r" (id | FUTEX_WAITERS), "r" (__futex) \ +	: "r0", "r1", "t", "memory"); \ +      if (__result) \ +	__result = __lll_robust_lock_wait (__result, __futex, private); \ +      __result; }) + +#define lll_timedlock(futex, timeout, private) \ +  ({ int __result, *__futex = &(futex); \ +     __asm __volatile ("\ +	.align 2\n\ +	mova 1f,r0\n\ +	nop\n\ +	mov r15,r1\n\ +	mov #-8,r15\n\ +     0: mov.l @%2,%0\n\ +	tst %0,%0\n\ +	bf 1f\n\ +	mov.l %1,@%2\n\ +     1: mov r1,r15"\ +	: "=&r" (__result) : "r" (1), "r" (__futex) \ +	: "r0", "r1", "t", "memory"); \ +    if (__result) \ +      __result = __lll_timedlock_wait (__result, __futex, timeout, private); \ +    __result; }) + +#define lll_robust_timedlock(futex, timeout, id, private) \ +  ({ int __result, *__futex = &(futex); \ +     __asm __volatile ("\ +	.align 2\n\ +	mova 1f,r0\n\ +	nop\n\ +	mov r15,r1\n\ +	mov #-8,r15\n\ +     0: mov.l @%2,%0\n\ +	tst %0,%0\n\ +	bf 1f\n\ +	mov.l %1,@%2\n\ +     1: mov r1,r15"\ +	: "=&r" (__result) : "r" (id), "r" (__futex) \ +	: "r0", "r1", "t", "memory"); \ +    if (__result) \ +      __result = __lll_robust_timedlock_wait (__result, __futex, \ +					      timeout, private); \ +    __result; }) + +#define lll_unlock(futex, private) \ +  (void) ({ int __result, *__futex = &(futex); \ +	    __asm __volatile ("\ +		.align 2\n\ +		mova 1f,r0\n\ +		mov r15,r1\n\ +		mov #-6,r15\n\ +	     0: mov.l @%1,%0\n\ +		add #-1,%0\n\ +		mov.l %0,@%1\n\ +	     1: mov r1,r15"\ +		: "=&r" (__result) : "r" (__futex) \ +		: "r0", "r1", "memory"); \ +	    if (__result) \ +	      { \ +		if (__builtin_constant_p (private) \ +		    && (private) == LLL_PRIVATE) \ +		  __lll_unlock_wake_private (__futex); \ +	        else \ +		  __lll_unlock_wake (__futex, (private)); \ +	      } \ +    }) + +#define lll_robust_unlock(futex, private) \ +  (void) ({ int __result, *__futex = &(futex); \ +	    __asm __volatile ("\ +		.align 2\n\ +		mova 1f,r0\n\ +		mov r15,r1\n\ +		mov #-6,r15\n\ +	     0: mov.l @%1,%0\n\ +		and %2,%0\n\ +		mov.l %0,@%1\n\ +	     1: mov r1,r15"\ +		: "=&r" (__result) : "r" (__futex), "r" (FUTEX_WAITERS) \ +		: "r0", "r1", "memory");	\ +	    if (__result) \ +	      __lll_unlock_wake (__futex, private); }) + +#define lll_robust_dead(futex, private)		       \ +  (void) ({ int __ignore, *__futex = &(futex); \ +	    __asm __volatile ("\ +		.align 2\n\ +		mova 1f,r0\n\ +		mov r15,r1\n\ +		mov #-6,r15\n\ +	     0: mov.l @%1,%0\n\ +		or %2,%0\n\ +		mov.l %0,@%1\n\ +	     1: mov r1,r15"\ +		: "=&r" (__ignore) : "r" (__futex), "r" (FUTEX_OWNER_DIED) \ +		: "r0", "r1", "memory");	\ +	    lll_futex_wake (__futex, 1, private); }) + +# ifdef NEED_SYSCALL_INST_PAD +#  define SYSCALL_WITH_INST_PAD "\ +	trapa #0x14; or r0,r0; or r0,r0; or r0,r0; or r0,r0; or r0,r0" +# else +#  define SYSCALL_WITH_INST_PAD "\ +	trapa #0x14" +# endif + +#define lll_futex_wait(futex, val, private) \ +  lll_futex_timed_wait (futex, val, NULL, private) + + +#define lll_futex_timed_wait(futex, val, timeout, private) \ +  ({									      \ +    int __status;							      \ +    register unsigned long __r3 __asm ("r3") = SYS_futex;			      \ +    register unsigned long __r4 __asm ("r4") = (unsigned long) (futex);	      \ +    register unsigned long __r5 __asm ("r5")				      \ +      = __lll_private_flag (FUTEX_WAIT, private);			      \ +    register unsigned long __r6 __asm ("r6") = (unsigned long) (val);	      \ +    register unsigned long __r7 __asm ("r7") = (timeout);			      \ +    __asm __volatile (SYSCALL_WITH_INST_PAD				      \ +		      : "=z" (__status)					      \ +		      : "r" (__r3), "r" (__r4), "r" (__r5),		      \ +			"r" (__r6), "r" (__r7)				      \ +		      : "memory", "t");					      \ +    __status;								      \ +  }) + + +#define lll_futex_wake(futex, nr, private) \ +  do {									      \ +    int __ignore;							      \ +    register unsigned long __r3 __asm ("r3") = SYS_futex;			      \ +    register unsigned long __r4 __asm ("r4") = (unsigned long) (futex);	      \ +    register unsigned long __r5 __asm ("r5")				      \ +      = __lll_private_flag (FUTEX_WAKE, private);			      \ +    register unsigned long __r6 __asm ("r6") = (unsigned long) (nr);	      \ +    register unsigned long __r7 __asm ("r7") = 0;				      \ +    __asm __volatile (SYSCALL_WITH_INST_PAD				      \ +		      : "=z" (__ignore)					      \ +		      : "r" (__r3), "r" (__r4), "r" (__r5),		      \ +			"r" (__r6), "r" (__r7)				      \ +		      : "memory", "t");					      \ +  } while (0) + + +#define lll_islocked(futex) \ +  (futex != LLL_LOCK_INITIALIZER) + +/* The kernel notifies a process with uses CLONE_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(tid) \ +  do {									      \ +    __typeof (tid) *__tid = &(tid);					      \ +    while (*__tid != 0)							      \ +      lll_futex_wait (__tid, *__tid, LLL_SHARED);			      \ +  } while (0) + +extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime) +     attribute_hidden; +#define lll_timedwait_tid(tid, abstime) \ +  ({									      \ +    int __result = 0;							      \ +    if (tid != 0)							      \ +      {									      \ +	if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)	      \ +	  __result = EINVAL;						      \ +	else								      \ +	  __result = __lll_timedwait_tid (&tid, abstime);		      \ +      }									      \ +    __result; }) + +#endif  /* !__ASSEMBLER__ */ + +#endif  /* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevelrobustlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevelrobustlock.S new file mode 100644 index 000000000..1e05a56c0 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevelrobustlock.S @@ -0,0 +1,265 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2007 +   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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <lowlevellock.h> +#include <lowlevelrobustlock.h> +#include <bits/kernel-features.h> +#include <tcb-offsets.h> +#include "lowlevel-atomic.h" + +	.text + +#define FUTEX_WAITERS		0x80000000 +#define FUTEX_OWNER_DIED	0x40000000 + +#ifdef __ASSUME_PRIVATE_FUTEX +# define LOAD_FUTEX_WAIT(reg,tmp,tmp2) \ +	mov	#(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), tmp; \ +	extu.b	tmp, tmp; \ +	xor	tmp, reg +#else +# if FUTEX_WAIT == 0 +#  define LOAD_FUTEX_WAIT(reg,tmp,tmp2) \ +	stc	gbr, tmp	; \ +	mov.w	99f, tmp2	; \ +	add	tmp2, tmp 	; \ +	mov.l	@tmp, tmp2	; \ +	bra	98f		; \ +	 mov	#FUTEX_PRIVATE_FLAG, tmp ; \ +99:	.word	PRIVATE_FUTEX - TLS_PRE_TCB_SIZE ; \ +98:	extu.b	tmp, tmp	; \ +	xor	tmp, reg	; \ +	and	tmp2, reg +# else +#  define LOAD_FUTEX_WAIT(reg,tmp,tmp2) \ +	stc	gbr, tmp	; \ +	mov.w	99f, tmp2	; \ +	add	tmp2, tmp 	; \ +	mov.l	@tmp, tmp2	; \ +	bra	98f		; \ +	 mov	#FUTEX_PRIVATE_FLAG, tmp ; \ +99:	.word	PRIVATE_FUTEX - TLS_PRE_TCB_SIZE ; \ +98:	extu.b	tmp, tmp	; \ +	xor	tmp, reg	; \ +	and	tmp2, reg	; \ +	mov	#FUTEX_WAIT, tmp ; \ +	or	tmp, reg +# endif +#endif + +	.globl	__lll_robust_lock_wait +	.type	__lll_robust_lock_wait,@function +	.hidden	__lll_robust_lock_wait +	.align	5 +	cfi_startproc +__lll_robust_lock_wait: +	mov.l	r8, @-r15 +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset (r8, 0) +	mov	r5, r8 +	mov	#0, r7		/* No timeout.  */ +	mov	r6, r5 +	LOAD_FUTEX_WAIT (r5, r0, r1) + +4: +	mov	r4, r6 +	mov.l	.L_FUTEX_WAITERS, r0 +	or	r0, r6 +	shlr	r0		/* r0 = FUTEX_OWNER_DIED */ +	tst	r0, r4 +	bf/s	3f +	 cmp/eq	r4, r6 +	bt	1f + +	CMPXCHG (r4, @r8, r6, r2) +	bf	2f + +1: +	mov	r8, r4 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD + +	mov.l	@r8, r2 + +2: +	tst	r2, r2 +	bf/s	4b +	 mov	r2, r4 + +	stc	gbr, r1 +	mov.w	.Ltidoff, r2 +	add	r2, r1 +	mov.l	@r1, r6 +	mov	#0, r3 +	CMPXCHG (r3, @r8, r6, r4) +	bf	4b +	mov	#0, r4 + +3: +	mov.l	@r15+, r8 +	ret +	 mov	r4, r0 +	cfi_endproc +	.align	2 +.L_FUTEX_WAITERS: +	.long	FUTEX_WAITERS +.Ltidoff: +	.word	TID - TLS_PRE_TCB_SIZE +	.size	__lll_robust_lock_wait,.-__lll_robust_lock_wait + + +	.globl	__lll_robust_timedlock_wait +	.type	__lll_robust_timedlock_wait,@function +	.hidden	__lll_robust_timedlock_wait +	.align	5 +	cfi_startproc +__lll_robust_timedlock_wait: +	/* Check for a valid timeout value.  */ +	mov.l	@(4,r6), r1 +	mov.l	.L1g, r0 +	cmp/hs	r0, r1 +	bt	3f + +	mov.l	r11, @-r15 +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset (r11, 0) +	mov.l	r10, @-r15 +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset (r10, 0) +	mov.l	r9, @-r15 +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset (r9, 0) +	mov.l	r8, @-r15 +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset (r8, 0) +	mov	r7, r11 +	mov	r4, r10 +	mov	r6, r9 +	mov	r5, r8 + +	/* Stack frame for the timespec and timeval structs.  */ +	add	#-8, r15 +	cfi_adjust_cfa_offset(8) + +1: +	/* Get current time.  */ +	mov	r15, r4 +	mov	#0, r5 +	mov	#__NR_gettimeofday, r3 +	trapa	#0x12 +	SYSCALL_INST_PAD + +	/* Compute relative timeout.  */ +	mov.l	@(4,r15), r0 +	mov.w	.L1k, r1 +	dmulu.l	r0, r1		/* Micro seconds to nano seconds.  */ +	mov.l	@r9, r2 +	mov.l	@(4,r9), r3 +	mov.l	@r15, r0 +	sts	macl, r1 +	sub	r0, r2 +	clrt +	subc	r1, r3 +	bf	4f +	mov.l	.L1g, r1 +	add	r1, r3 +	add	#-1, r2 +4: +	cmp/pz	r2 +	bf	8f		/* Time is already up.  */ + +	mov.l	r2, @r15	/* Store relative timeout.  */ +	mov.l	r3, @(4,r15) + +	mov	r10, r6 +	mov.l	.L_FUTEX_WAITERS2, r0 +	or	r0, r6 +	shlr	r0		/* r0 = FUTEX_OWNER_DIED */ +	tst	r0, r4 +	bf/s	6f +	 cmp/eq	r4, r6 +	bt	2f + +	CMPXCHG (r4, @r8, r6, r2) +	bf/s	5f +	 mov	#0, r5 + +2: +	mov	r8, r4 +	mov	r11, r5 +	LOAD_FUTEX_WAIT (r5, r0, r1) +	mov	r10, r6 +	mov	r15, r7 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD +	mov	r0, r5 + +	mov.l	@r8, r2 + +5: +	tst	r2, r2 +	bf/s	7f +	 mov	r2, r10 + +	stc	gbr, r1 +	mov.w	.Ltidoff2, r2 +	add	r2, r1 +	mov.l	@r1, r4 +	mov	#0, r3 +	CMPXCHG (r3, @r8, r4, r10) +	bf	7f +	mov	#0, r0 + +6: +	add	#8, r15 +	mov.l	@r15+, r8 +	mov.l	@r15+, r9 +	mov.l	@r15+, r10 +	rts +	 mov.l	@r15+, r11 + +7: +	/* Check whether the time expired.  */ +	mov	#-ETIMEDOUT, r1 +	cmp/eq	r5, r1 +	bf	1b + +8: +	bra	6b +	 mov	#ETIMEDOUT, r0 +3: +	rts +	 mov	#EINVAL, r0 +	cfi_endproc +	.align	2 +.L_FUTEX_WAITERS2: +	.long	FUTEX_WAITERS +.L1g: +	.long	1000000000 +.Ltidoff2: +	.word	TID - TLS_PRE_TCB_SIZE +.L1k: +	.word	1000 +	.size	__lll_robust_timedlock_wait,.-__lll_robust_timedlock_wait diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pt-initfini.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pt-initfini.c new file mode 100644 index 000000000..82c97c352 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pt-initfini.c @@ -0,0 +1,126 @@ +/* Special .init and .fini section support for SH.  NPTL version. +   Copyright (C) 2003, 2009 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 Library General Public +   License as published by the Free Software Foundation; either +   version 2 of the License, or (at your option) any later version. + +   In addition to the permissions in the GNU Library General Public +   License, the Free Software Foundation gives you unlimited +   permission to link the compiled version of this file with other +   programs, and to distribute those programs without any restriction +   coming from the use of this file.  (The Library General Public +   License restrictions do apply in other respects; for example, they +   cover modification of the file, and distribution when not linked +   into another program.) + +   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 Library General Public License for more details. + +   You should have received a copy of the GNU Library General Public +   License along with the GNU C Library; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +/* This file is compiled into assembly code which is then munged by a sed +   script into two files: crti.s and crtn.s. + +   * crti.s puts a function prologue at the beginning of the +   .init and .fini sections and defines global symbols for +   those addresses, so they can be called as functions. + +   * crtn.s puts the corresponding function epilogues +   in the .init and .fini sections. */ + +__asm__ ("\n\ +\n\ +#include \"defs.h\"\n\ +\n\ +/*@HEADER_ENDS*/\n\ +\n\ +/*@TESTS_BEGIN*/\n\ +\n\ +/*@TESTS_END*/\n\ +\n\ +/*@_init_PROLOG_BEGINS*/\n\ +	.section .init\n\ +	.align 5\n\ +	.global	_init\n\ +	.type	_init,@function\n\ +_init:\n\ +	mov.l	r12,@-r15\n\ +	mov.l	r14,@-r15\n\ +	sts.l	pr,@-r15\n\ +	mova	.L22,r0\n\ +	mov.l	.L22,r12\n\ +	add	r0,r12\n\ +	mova	.L24,r0\n\ +	mov.l	.L24,r1\n\ +	add	r0,r1\n\ +	jsr	@r1\n\ +	 mov	r15,r14\n\ +	bra	1f\n\ +	 nop\n\ +	.align 2\n\ +.L22:\n\ +	.long	_GLOBAL_OFFSET_TABLE_\n\ +.L24:\n\ +	.long	__pthread_initialize_minimal_internal@PLT\n\ +1:\n\ +	ALIGN\n\ +	END_INIT\n\ +\n\ +/*@_init_PROLOG_ENDS*/\n\ +\n\ +/*@_init_EPILOG_BEGINS*/\n\ +	.section .init\n\ +	mov	r14,r15\n\ +	lds.l	@r15+,pr\n\ +	mov.l	@r15+,r14\n\ +	rts	\n\ +	mov.l	@r15+,r12\n\ +	END_INIT\n\ +	\n\ +/*@_init_EPILOG_ENDS*/\n\ +\n\ +/*@_fini_PROLOG_BEGINS*/\n\ +	.section .fini\n\ +	.align 5\n\ +	.global	_fini\n\ +	.type	_fini,@function\n\ +_fini:\n\ +	mov.l	r12,@-r15\n\ +	mov.l	r14,@-r15\n\ +	sts.l	pr,@-r15\n\ +	mova	.L27,r0\n\ +	mov.l	.L27,r12\n\ +	add	r0,r12\n\ +	mov	r15,r14\n\ +	ALIGN\n\ +	END_FINI\n\ +	bra	1f\n\ +	 nop\n\ +	.align	2\n\ +.L27:\n\ +	.long	_GLOBAL_OFFSET_TABLE_\n\ +1:\n\ +/*@_fini_PROLOG_ENDS*/\n\ +\n\ +/*@_fini_EPILOG_BEGINS*/\n\ +	.section .fini\n\ +	mov	r14,r15\n\ +	lds.l	@r15+,pr\n\ +	mov.l	@r15+,r14\n\ +	rts	\n\ +	mov.l	@r15+,r12\n\ +\n\ +	END_FINI\n\ +	\n\ +/*@_fini_EPILOG_ENDS*/\n\ +\n\ +/*@TRAILER_BEGINS*/\n\ +"); diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pt-vfork.S new file mode 100644 index 000000000..54f2281d7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pt-vfork.S @@ -0,0 +1,65 @@ +/* Copyright (C) 2003, 2004 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#define _ERRNO_H	1 +#include <bits/errno.h> +#include <tcb-offsets.h> + +/* Clone the calling process, but without copying the whole address space. +   The calling process is suspended until the new process exits or is +   replaced by a call to `execve'.  Return -1 for errors, 0 to the new process, +   and the process ID of the new process to the old process.  */ + +ENTRY (__vfork) +	/* Save the PID value.  */ +	stc	gbr, r2 +	mov.w	.L2, r0 +	mov.l	@(r0,r2), r4 +	neg	r4, r1 +	mov.l	r1, @(r0,r2) + +	mov.w	.L1, r3 +	trapa	#0x10 +	mov     r0, r1 + +	/* Restore the old PID value in the parent.  */ +	tst	r0, r0 +	bt/s	2f +	 stc	gbr, r2 +	mov.w	.L2, r0 +	mov.l	r4, @(r0,r2) +	mov	r1, r0 +2: +	mov	#-12, r2 +	shad	r2, r1 +	not	r1, r1			// r1=0 means r0 = -1 to -4095 +	tst	r1, r1			// i.e. error in linux +	bf	.Lpseudo_end +	SYSCALL_ERROR_HANDLER +.Lpseudo_end: +	rts +	 nop +.L1: +	.word	__NR_vfork +.L2: +	.word	PID - TLS_PRE_TCB_SIZE + +PSEUDO_END (__vfork) + +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S new file mode 100644 index 000000000..4a6059aef --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S @@ -0,0 +1,216 @@ +/* Copyright (C) 2003, 2004, 2007, 2008 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelbarrier.h> +#include "lowlevel-atomic.h" + +	.text + +	.globl	pthread_barrier_wait +	.type	pthread_barrier_wait,@function +	.align	5 +pthread_barrier_wait: +	mov.l	r9, @-r15 +	mov.l	r8, @-r15 +	sts.l	pr, @-r15 +	mov	r4, r8 + +	/* Get the mutex.  */ +	mov	#0, r3 +	mov	#1, r4 +	CMPXCHG (r3, @(MUTEX,r8), r4, r2) +	bf	1f + +	/* One less waiter.  If this was the last one needed wake +	   everybody.  */ +2: +	mov.l	@(LEFT,r8), r0 +	add	#-1, r0 +	mov.l	r0, @(LEFT,r8) +	tst	r0, r0 +	bt	3f + +	/* There are more threads to come.  */ +	mov.l	@(CURR_EVENT,r8), r6 + +	/* Release the mutex.  */ +	DEC (@(MUTEX,r8), r2) +	tst	r2, r2 +	bf	6f +7: +	/* Wait for the remaining threads.  The call will return immediately +	   if the CURR_EVENT memory has meanwhile been changed.  */ +	mov	r8, r4 +#if CURR_EVENT != 0 +	add	#CURR_EVENT, r4 +#endif +#if FUTEX_WAIT == 0 +	mov.l	@(PRIVATE,r8), r5 +#else +	mov	#FUTEX_WAIT, r5 +	mov.l	@(PRIVATE,r8), r0 +	or	r0, r5 +#endif +	mov	#0, r7 +8: +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD + +	/* Don't return on spurious wakeups.  The syscall does not change +	   any register except r0 so there is no need to reload any of +	   them.  */ +	mov.l	@(CURR_EVENT,r8), r0 +	cmp/eq	r0, r6 +	bt	8b + +	/* Increment LEFT.  If this brings the count back to the +	   initial count unlock the object.  */ +	mov	#1, r3 +	mov.l	@(INIT_COUNT,r8), r4 +	XADD	(r3, @(LEFT,r8), r2, r5) +	add	#-1, r4 +	cmp/eq	r2, r4 +	bf	10f + +	/* Release the mutex.  We cannot release the lock before +	   waking the waiting threads since otherwise a new thread might +	   arrive and gets waken up, too.  */ +	DEC (@(MUTEX,r8), r2) +	tst	r2, r2 +	bf	9f + +10: +	mov	#0, r0		/* != PTHREAD_BARRIER_SERIAL_THREAD */ +	lds.l	@r15+, pr +	mov.l	@r15+, r8 +	rts +	 mov.l	@r15+, r9 + +3: +	/* The necessary number of threads arrived.  */ +	mov.l	@(CURR_EVENT,r8), r1 +	add	#1, r1 +	mov.l	r1, @(CURR_EVENT,r8) + +	/* Wake up all waiters.  The count is a signed number in the kernel +	   so 0x7fffffff is the highest value.  */ +	mov.l	.Lall, r6 +	mov	r8, r4 +#if CURR_EVENT != 0 +	add	#CURR_EVENT, r4 +#endif +	mov	#0, r7 +	mov	#FUTEX_WAKE, r5 +	mov.l	@(PRIVATE,r8), r0 +	or	r0, r5 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD + +	/* Increment LEFT.  If this brings the count back to the +	   initial count unlock the object.  */ +	mov	#1, r3 +	mov.l	@(INIT_COUNT,r8), r4 +	XADD	(r3, @(LEFT,r8), r2, r5) +	add	#-1, r4 +	cmp/eq	r2, r4 +	bf	5f + +	/* Release the mutex.  */ +	DEC (@(MUTEX,r8), r2) +	tst	r2, r2 +	bf	4f +5: +	mov	#-1, r0		/* == PTHREAD_BARRIER_SERIAL_THREAD */ +	lds.l	@r15+, pr +	mov.l	@r15+, r8 +	rts +	 mov.l	@r15+, r9 + +1: +	mov.l	@(PRIVATE,r8), r6 +	mov	#LLL_SHARED, r0 +	extu.b	r0, r0 +	xor	r0, r6 +	mov	r2, r4 +	mov	r8, r5 +	mov.l	.Lwait0, r1 +	bsrf	r1 +	 add	#MUTEX, r5 +.Lwait0b: +	bra	2b +	 nop + +4: +	mov.l	@(PRIVATE,r8), r5 +	mov	#LLL_SHARED, r0 +	extu.b	r0, r0 +	xor	r0, r5 +	mov	r8, r4 +	mov.l	.Lwake0, r1 +	bsrf	r1 +	 add	#MUTEX, r4 +.Lwake0b: +	bra	5b +	 nop + +6: +	mov	r6, r9 +	mov.l	@(PRIVATE,r8), r5 +	mov	#LLL_SHARED, r0 +	extu.b	r0, r0 +	xor	r0, r5 +	mov	r8, r4 +	mov.l	.Lwake1, r1 +	bsrf	r1 +	 add	#MUTEX, r4 +.Lwake1b: +	bra	7b +	 mov	r9, r6 + +9:	 +	mov	r6, r9 +	mov.l	@(PRIVATE,r8), r5 +	mov	#LLL_SHARED, r0 +	extu.b	r0, r0 +	xor	r0, r5 +	mov	r8, r4 +	mov.l	.Lwake2, r1 +	bsrf	r1 +	 add	#MUTEX, r4 +.Lwake2b: +	bra	10b +	 mov	r9, r6 + +	.align	2 +.Lall: +	.long	0x7fffffff +.Lwait0: +	.long	__lll_lock_wait-.Lwait0b +.Lwake0: +	.long	__lll_unlock_wake-.Lwake0b +.Lwake1: +	.long	__lll_unlock_wake-.Lwake1b +.Lwake2: +	.long	__lll_unlock_wake-.Lwake2b +	.size	pthread_barrier_wait,.-pthread_barrier_wait diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S new file mode 100644 index 000000000..233183177 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S @@ -0,0 +1,263 @@ +/* Copyright (C) 2003, 2004, 2006, 2007 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelcond.h> +#include <bits/kernel-features.h> +#include <pthread-pi-defines.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include "lowlevel-atomic.h" + +	.text + +	/* int pthread_cond_broadcast (pthread_cond_t *cond) */ +	.globl	__pthread_cond_broadcast +	.type	__pthread_cond_broadcast, @function +	.protected	__pthread_cond_broadcast +	.align	5 +__pthread_cond_broadcast: +	mov.l   r10, @-r15 +	mov.l   r9, @-r15 +	mov.l	r8, @-r15 +	sts.l	pr, @-r15 +	mov	r4, r8 + +	/* Get internal lock.  */ +	mov	#0, r3 +	mov	#1, r4 +#if cond_lock != 0 +	CMPXCHG (r3, @(cond_lock,r8), r4, r2) +#else +	CMPXCHG (r3, @r8, r4, r2) +#endif +	bf	1f +2: +	mov.l	@(total_seq+4,r8),r0 +	mov.l	@(total_seq,r8),r1 +	mov.l	@(wakeup_seq+4,r8), r2 +	cmp/hi	r2, r0 +	bt	3f +	cmp/hi	r0, r2 +	bt	4f +	mov.l	@(wakeup_seq,r8), r2 +	cmp/hi	r2, r1 +	bf	4f + +3: +	/* Cause all currently waiting threads to recognize they are +	   woken up.  */ +	mov.l	r1, @(wakeup_seq,r8) +	mov.l	r0, @(wakeup_seq+4,r8) +	mov.l	r1, @(woken_seq,r8) +	mov.l	r0, @(woken_seq+4,r8) +	mov.l	@(broadcast_seq,r8), r2 +	add	#1, r2 +	mov.l	r2, @(broadcast_seq,r8) +	add	r1, r1 +	mov	r1, r10 +	mov.l	r10, @(cond_futex,r8) + +	/* Get the address of the mutex used.  */ +	mov.l	@(dep_mutex,r8), r9 + +	/* Unlock.  */ +#if cond_lock != 0 +	DEC (@(cond_lock,r8), r2) +#else +	DEC (@r8, r2) +#endif +	tst	r2, r2 +	bf	7f + +8: +	/* Don't use requeue for pshared condvars.  */ +	mov	#-1, r0 +	cmp/eq	r0, r9 +	mov	r8, r4 +	bt/s	9f +	 add	#cond_futex, r4 + +	/* XXX: The kernel only supports FUTEX_CMP_REQUEUE to the same +	   type of futex (private resp. shared).  */ +	mov.l	@(MUTEX_KIND,r9), r0 +	tst	#(PI_BIT|PS_BIT), r0 +	bf	9f + +	/* Wake up all threads.  */ +#ifdef __ASSUME_PRIVATE_FUTEX +	mov	#(FUTEX_CMP_REQUEUE|FUTEX_PRIVATE_FLAG), r5 +	extu.b	r5, r5 +#else +	stc	gbr, r1 +	mov.w	.Lpfoff, r2 +	add	r2, r1 +	mov.l	@r1, r5 +	mov	#FUTEX_CMP_REQUEUE, r0 +	or	r0, r5 +#endif +	mov	#1, r6 +	mov	#-1, r7 +	shlr	r7		/* r7 = 0x7fffffff */ +	mov	r9, r0 +# if MUTEX_FUTEX != 0 +	add	#MUTEX_FUTEX, r0 +# endif +	mov	r10, r1 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x16 +	SYSCALL_INST_PAD + +	/* For any kind of error, which mainly is EAGAIN, we try again +	   with WAKE.  The general test also covers running on old +	   kernels.  */ +	mov	r0, r1 +	mov	#-12, r2 +	shad	r2, r1 +	not	r1, r1 +	tst	r1, r1 +	mov	r8, r4 +	bt/s	9f +	 add	#cond_futex, r4 + +10: +	mov	#0, r0 +	lds.l	@r15+, pr +	mov.l	@r15+, r8 +	mov.l	@r15+, r9 +	rts +	 mov.l	@r15+, r10 + +4: +	/* Unlock.  */ +#if cond_lock != 0 +	DEC (@(cond_lock,r8), r2) +#else +	DEC (@r8, r2) +#endif +	tst	r2, r2 +	bf	5f +6: +	mov	#0, r0 +	lds.l	@r15+, pr +	mov.l	@r15+, r8 +	mov.l	@r15+, r9 +	rts +	 mov.l	@r15+, r10 + +1: +	/* Initial locking failed.  */ +	mov	r8, r5 +#if cond_lock != 0 +	add	#cond_lock, r5 +#endif +	mov.l	@(dep_mutex,r8), r0 +	cmp/eq	#-1, r0 +	bf/s	99f +	 mov	#LLL_PRIVATE, r6 +	mov	#LLL_SHARED, r6 +99: +	extu.b	r6, r6 +	mov.l	.Lwait5, r1 +	bsrf	r1 +	 mov	r2, r4 +.Lwait5b: +	bra	2b +	 nop + +5: +	/* Unlock in loop requires wakeup.  */ +	mov	r8, r4 +#if cond_lock != 0 +	add	#cond_lock, r4 +#endif +	mov.l	@(dep_mutex,r8), r0 +	cmp/eq	#-1, r0 +	bf/s	99f +	 mov	#LLL_PRIVATE, r5 +	mov	#LLL_SHARED, r5 +99: +	mov.l	.Lwake5, r1 +	bsrf	r1 +	 extu.b	r5, r5 +.Lwake5b: +	bra	6b +	 nop + +7: +	/* Unlock in loop requires wakeup.  */ +	mov	r8, r4 +#if cond_lock != 0 +	add	#cond_lock, r4 +#endif +	mov	#-1, r0 +	cmp/eq	r0, r9 +	bf/s	99f +	 mov	#LLL_PRIVATE, r5 +	mov	#LLL_SHARED, r5 +99: +	mov.l	.Lwake6, r1 +	bsrf	r1 +	 extu.b	r5, r5 +.Lwake6b: +	bra	8b +	 nop + +9: +	mov	#-1, r0 +	cmp/eq	r0, r9 +	bt/s	99f +	 mov	#FUTEX_WAKE, r5 +#ifdef __ASSUME_PRIVATE_FUTEX +	mov	#(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), r5 +	extu.b	r5, r5 +#else +	stc	gbr, r1 +	mov.w	.Lpfoff, r2 +	add	r2, r1 +	mov.l	@r1, r5 +	mov	#FUTEX_WAKE, r0 +	or	r0, r5 +#endif +99: +	mov	#-1, r6 +	shlr	r6		/* r6 = 0x7fffffff */ +	mov	#0, r7 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD +	bra	10b +	 nop + +#ifndef __ASSUME_PRIVATE_FUTEX +.Lpfoff: +	.word	PRIVATE_FUTEX - TLS_PRE_TCB_SIZE +#endif + +	.align	2 +.Lwait5: +	.long	__lll_lock_wait-.Lwait5b +.Lwake5: +	.long	__lll_unlock_wake-.Lwake5b +.Lwake6: +	.long	__lll_unlock_wake-.Lwake6b +	.size	__pthread_cond_broadcast, .-__pthread_cond_broadcast +weak_alias (__pthread_cond_broadcast, pthread_cond_broadcast) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S new file mode 100644 index 000000000..ca87336d9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S @@ -0,0 +1,190 @@ +/* Copyright (C) 2003, 2004, 2007 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelcond.h> +#include <bits/kernel-features.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include "lowlevel-atomic.h" + +	.text + +	/* int pthread_cond_signal (pthread_cond_t *cond) */ +	.globl	__pthread_cond_signal +	.type	__pthread_cond_signal, @function +	.protected	__pthread_cond_signal +	.align	5 +__pthread_cond_signal: +	mov.l	r8, @-r15 +	sts.l	pr, @-r15 +	mov	r4, r8 + +	/* Get internal lock.  */ +	mov	#0, r3 +	mov	#1, r4 +#if cond_lock != 0 +	CMPXCHG (r3, @(cond_lock,r8), r4, r2) +#else +	CMPXCHG (r3, @r8, r4, r2) +#endif +	bf	1f +2: +	mov.l	@(total_seq+4,r8),r0 +	mov.l	@(total_seq,r8),r1 +	mov.l	@(wakeup_seq+4,r8), r2 +	cmp/hi	r2, r0 +	bt	3f +	cmp/hi	r0, r2 +	bt	4f +	mov.l	@(wakeup_seq,r8), r2 +	cmp/hi	r2, r1 +	bf	4f + +3: +	/* Bump the wakeup number.  */ +	mov	#1, r2 +	mov	#0, r3 +	clrt +	mov.l	@(wakeup_seq,r8),r0 +	mov.l	@(wakeup_seq+4,r8),r1 +	addc	r2, r0 +	addc	r3, r1 +	mov.l	r0,@(wakeup_seq,r8) +	mov.l	r1,@(wakeup_seq+4,r8) +	mov.l	@(cond_futex,r8),r0 +	add	r2, r0 +	mov.l	r0,@(cond_futex,r8) + +	/* Wake up one thread.  */ +	mov	r8, r4 +	add	#cond_futex, r4 +	mov.l	@(dep_mutex,r8), r0 +	cmp/eq	#-1, r0 +	bt/s	99f +	 mov	#FUTEX_WAKE_OP, r5 +#ifdef __ASSUME_PRIVATE_FUTEX +	mov	#(FUTEX_WAKE_OP|FUTEX_PRIVATE_FLAG), r5 +	extu.b	r5, r5 +#else +	stc	gbr, r1 +	mov.w	.Lpfoff, r2 +	add	r2, r1 +	mov.l	@r1, r5 +	mov	#FUTEX_WAKE_OP, r0 +	or	r0, r5 +#endif +99: +	mov	#1, r6 +	mov	#0, r7 +	mov	r8, r0 +	add	#cond_lock, r0 +	mov.l	.Lfutexop, r1 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD + +	/* For any kind of error, we try again with WAKE. +	   The general test also covers running on old kernels.  */ +	mov	r0, r1 +	mov	#-12, r2 +	shad	r2, r1 +	not	r1, r1 +	tst	r1, r1 +	bt	7f + +6: +	mov	#0, r0 +	lds.l	@r15+, pr +	rts +	 mov.l	@r15+, r8 + +#ifndef __ASSUME_PRIVATE_FUTEX +.Lpfoff: +	.word	PRIVATE_FUTEX - TLS_PRE_TCB_SIZE +#endif +	.align	2 +.Lfutexop: +	.long	FUTEX_OP_CLEAR_WAKE_IF_GT_ONE + +7: +	/* r5 should be either FUTEX_WAKE_OP or +	   FUTEX_WAKE_OP|FUTEX_PRIVATE_FLAG from the previous syscall.  */ +	mov	#(FUTEX_WAKE ^ FUTEX_WAKE_OP), r0 +	xor	r0, r5 +	trapa	#0x14 +	SYSCALL_INST_PAD + +4: +	/* Unlock.  */ +#if cond_lock != 0 +	DEC (@(cond_lock,r8), r2) +#else +	DEC (@r8, r2) +#endif +	tst	r2, r2 +	bt	6b + +5: +	/* Unlock in loop requires wakeup.  */ +	mov	r8, r4 +#if cond_lock != 0 +	add	#cond_lock, r4 +#endif +	mov.l	@(dep_mutex,r8), r0 +	cmp/eq	#-1, r0 +	bf/s	99f +	 mov	#LLL_PRIVATE, r5 +	mov	#LLL_SHARED, r5 +99:	 +	mov.l	.Lwake4, r1 +	bsrf	r1 +	 extu.b	r5, r5 +.Lwake4b: +	bra	6b +	 nop + +1: +	/* Initial locking failed.  */ +	mov	r8, r5 +#if cond_lock != 0 +	add	#cond_lock, r5 +#endif +	mov.l	@(dep_mutex,r8), r0 +	cmp/eq	#-1, r0 +	bf/s	99f +	 mov	#LLL_PRIVATE, r6 +	mov	#LLL_SHARED, r6 +99:	 +	extu.b	r6, r6 +	mov.l	.Lwait4, r1 +	bsrf	r1 +	 mov	r2, r4 +.Lwait4b: +	bra	2b +	 nop + +	.align	2 +.Lwait4: +	.long	__lll_lock_wait-.Lwait4b +.Lwake4: +	.long	__lll_unlock_wake-.Lwake4b +	.size	__pthread_cond_signal, .-__pthread_cond_signal +weak_alias (__pthread_cond_signal, pthread_cond_signal) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S new file mode 100644 index 000000000..cacb037d8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S @@ -0,0 +1,861 @@ +/* Copyright (C) 2003, 2004, 2006, 2007 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelcond.h> +#include <pthread-errnos.h> +#include <bits/kernel-features.h> +#include <tcb-offsets.h> +#include "lowlevel-atomic.h" + +	.text + +/* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, +			       const struct timespec *abstime)  */ +	.globl	__pthread_cond_timedwait +	.type	__pthread_cond_timedwait, @function +	.protected	__pthread_cond_timedwait +	.align	5 +__pthread_cond_timedwait: +.LSTARTCODE: +	mov.l	r8, @-r15 +.Lpush_r8: +	mov.l	r9, @-r15 +.Lpush_r9: +	mov.l	r10, @-r15 +.Lpush_r10: +	mov.l	r11, @-r15 +.Lpush_r11: +	mov.l	r12, @-r15 +.Lpush_r12: +	mov.l	r13, @-r15 +.Lpush_r13: +	sts.l	pr, @-r15 +.Lpush_pr: +	add	#-64, r15 +.Lalloc: +	mov	r4, r8 +	mov	r5, r9 +	mov	r6, r13 +#ifdef __PIC__ +	mova	.Lgot0, r0 +	mov.l	.Lgot0, r12 +	add	r0, r12 +#endif + +	mov.l	@(4,r13), r0 +	mov.l	.L1g, r1 +	cmp/hs	r1, r0 +	bf	0f +	bra	18f +	 mov	#EINVAL, r0 +0: +	/* Get internal lock.  */ +	mov	#0, r3 +	mov	#1, r4 +#if cond_lock != 0 +	CMPXCHG (r3, @(cond_lock,r8), r4, r2) +#else +	CMPXCHG (r3, @r8, r4, r2) +#endif +	bt	2f +	bra	1f +	 nop +#ifdef __PIC__ +	.align	2 +.Lgot0: +	.long	_GLOBAL_OFFSET_TABLE_ +#endif + +2: +	/* Store the reference to the mutex.  If there is already a +	   different value in there this is a bad user bug.  */ +	mov.l	@(dep_mutex,r8),r0 +	cmp/eq	#-1, r0 +	bt	17f +	mov.l	r9, @(dep_mutex,r8) + +17: +	/* Unlock the mutex.  */ +	mov.l	.Lmunlock1, r1 +	mov	#0, r5 +	bsrf	r1 +	 mov	r9, r4 +.Lmunlock1b: + +	tst	r0, r0 +	bt	0f +	bra	16f +	 nop +0: +	mov	#1, r2 +	mov	#0, r3 + +	clrt +	mov.l	@(total_seq,r8),r0 +	mov.l	@(total_seq+4,r8),r1 +	addc	r2, r0 +	addc	r3, r1 +	mov.l	r0,@(total_seq,r8) +	mov.l	r1,@(total_seq+4,r8) +	mov.l	@(cond_futex,r8), r0 +	add	r2, r0 +	mov.l	r0, @(cond_futex,r8) +	mov	#(1 << nwaiters_shift), r2 +	mov.l	@(cond_nwaiters,r8), r0 +	add	r2, r0 +	mov.l	r0, @(cond_nwaiters,r8) + +	/* Get and store current wakeup_seq value.  */ +	mov.l	@(wakeup_seq,r8), r10 +	mov.l	@(wakeup_seq+4,r8), r11 +	mov.l	@(broadcast_seq,r8), r0 +	mov.l	r0, @(4,r15) + +8: +	/* Get current time.  */ +#ifdef __NR_clock_gettime +	/* Get the clock number.	 */ +	mov.l	@(cond_nwaiters,r8), r4 +	mov	#((1 << nwaiters_shift) - 1), r0 +	and	r0, r4 +	/* Only clocks 0 and 1 are allowed.  Both are handled in the +	   kernel.  */ +	mov	r15, r5 +	add	#16, r5 +	mov.w	.L__NR_clock_gettime, r3 +	trapa	#0x12 +	SYSCALL_INST_PAD +# ifndef __ASSUME_POSIX_TIMERS +	cmp/eq	#-ENOSYS, r0 +	bt	19f +# endif + +	/* Compute relative timeout.  */ +	mov.l	@r13, r2 +	mov.l	@(4,r13), r3 +	mov.l	@(16,r15), r0 +	bra	0f +	 mov.l	@(20,r15), r1 +.L__NR_clock_gettime: +	.word	__NR_clock_gettime + +# ifndef __ASSUME_POSIX_TIMERS +19: +	mov	r15, r4 +	add	#16, r4 +	mov	#0, r5 +	mov	#__NR_gettimeofday, r3 +	trapa	#0x12 +	SYSCALL_INST_PAD + +	/* Compute relative timeout.  */ +	mov.l	@(20,r15), r0 +	mov.w	.L1k, r1 +	dmulu.l	r0, r1		/* Micro seconds to nano seconds.  */ +	mov.l	@r13, r2 +	mov.l	@(4,r13), r3 +	mov.l	@(16,r15), r0 +	sts	macl, r1 +#endif +0: +#else +	mov	r15, r4 +	add	#16, r4 +	mov	#0, r5 +	mov	#__NR_gettimeofday, r3 +	trapa	#0x12 +	SYSCALL_INST_PAD + +	/* Compute relative timeout.  */ +	mov.l	@(20,r15), r0 +	mov.w	.L1k, r1 +	dmulu.l	r0, r1		/* Micro seconds to nano seconds.  */ +	mov.l	@r13, r2 +	mov.l	@(4,r13), r3 +	mov.l	@(16,r15), r0 +	sts	macl, r1 +#endif +	sub	r0, r2 +	clrt +	subc	r1, r3 +	bf	12f +	mov.l	.L1g, r1 +	add	r1, r3 +	add	#-1, r2 +12: +	mov	#-ETIMEDOUT, r1 +	mov.l	r1, @(12,r15) +	cmp/pz	r2 +	bf	6f		/* Time is already up.  */ + +	/* Store relative timeout.  */ +	mov.l	r2, @(16,r15) +	mov.l	r3, @(20,r15) +	mov.l	@(cond_futex,r8), r1 +	mov.l	r1, @(8,r15) + +	/* Unlock.  */ +#if cond_lock != 0 +	DEC (@(cond_lock,r8), r2) +#else +	DEC (@r8, r2) +#endif +	tst	r2, r2 +	bt	4f +	bra	3f +	 nop +4: +.LcleanupSTART: +	mov.l	.Lenable1, r1 +	bsrf	r1 +	 nop +.Lenable1b: +	mov.l	r0, @r15 + +	mov	r15, r7 +	add	#16, r7 +	mov.l	@(dep_mutex,r8), r0 +	cmp/eq	#-1, r0 +	bt/s	99f +	 mov	#FUTEX_WAIT, r5 +#ifdef __ASSUME_PRIVATE_FUTEX +	mov	#(FUTEX_WAIT|FUTEX_PRIVATE_FLAG), r5 +	extu.b	r5, r5 +#else +	stc	gbr, r1 +	mov.w	.Lpfoff, r2 +	add	r2, r1 +	mov.l	@r1, r5 +	mov	#FUTEX_WAIT, r0 +	or	r0, r5 +#endif +99: +	mov.l	@(8,r15), r6 +	mov	r8, r4 +	add	#cond_futex, r4 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD +	mov.l	r0, @(12,r15) + +	mov.l	.Ldisable1, r1 +	bsrf	r1 +	 mov.l	@r15, r4 +.Ldisable1b: +.LcleanupEND: + +	/* Lock.  */ +	mov	#0, r3 +	mov	#1, r4 +#if cond_lock != 0 +	CMPXCHG (r3, @(cond_lock,r8), r4, r2) +#else +	CMPXCHG (r3, @r8, r4, r2) +#endif +	bf	5f +6: +	mov.l	@(broadcast_seq,r8), r0 +	mov.l	@(4,r15), r1 +	cmp/eq	r0, r1 +	bf	23f + +	mov.l	@(woken_seq,r8), r0 +	mov.l	@(woken_seq+4,r8), r1 + +	mov.l	@(wakeup_seq,r8), r2 +	mov.l	@(wakeup_seq+4,r8), r3 + +	cmp/eq	r3, r11 +	bf	7f +	cmp/eq	r2, r10 +	bt	15f +7: +	cmp/eq	r1, r3 +	bf	9f +	cmp/eq	r0, r2 +	bf	9f +15: +	mov.l	@(12,r15),r0 +	cmp/eq	#-ETIMEDOUT, r0 +	bf	8b + +	mov	#1, r2 +	mov	#0, r3 + +	clrt +	mov.l	@(wakeup_seq,r8),r0 +	mov.l	@(wakeup_seq+4,r8),r1 +	addc	r2, r0 +	addc	r3, r1 +	mov.l	r0,@(wakeup_seq,r8) +	mov.l	r1,@(wakeup_seq+4,r8) +	mov.l	@(cond_futex,r8),r0 +	add	r2, r0 +	mov.l	r0,@(cond_futex,r8) +	mov	#ETIMEDOUT, r0 +	bra	14f +	 mov.l	r0, @(24,r15) + +23: +	mov	#0, r0 +	bra	24f +	 mov.l	r0, @(24,r15) + +9: +	mov	#0, r0 +	mov.l	r0, @(24,r15) +14: +	mov	#1, r2 +	mov	#0, r3 + +	clrt +	mov.l	@(woken_seq,r8),r0 +	mov.l	@(woken_seq+4,r8),r1 +	addc	r2, r0 +	addc	r3, r1 +	mov.l	r0,@(woken_seq,r8) +	mov.l	r1,@(woken_seq+4,r8) + +24: +	mov	#(1 << nwaiters_shift), r2 +	mov.l	@(cond_nwaiters,r8),r0 +	sub	r2, r0 +	mov.l	r0,@(cond_nwaiters,r8) + +	/* Wake up a thread which wants to destroy the condvar object.  */ +	mov.l	@(total_seq,r8),r0 +	mov.l	@(total_seq+4,r8),r1 +	and	r1, r0 +	not	r0, r0 +	cmp/eq	#0, r0 +	bf/s	25f +	 mov	#((1 << nwaiters_shift) - 1), r1 +	not	r1, r1 +	mov.l	@(cond_nwaiters,r8),r0 +	tst	r1, r0 +	bf	25f + +	mov	r8, r4 +	add	#cond_nwaiters, r4 +	mov.l	@(dep_mutex,r8), r0 +	cmp/eq	#-1, r0 +	bt/s	99f +	 mov	#FUTEX_WAKE, r5 +#ifdef __ASSUME_PRIVATE_FUTEX +	mov	#(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), r5 +	extu.b	r5, r5 +#else +	stc	gbr, r1 +	mov.w	.Lpfoff, r2 +	add	r2, r1 +	mov.l	@r1, r5 +	mov	#FUTEX_WAKE, r0 +	or	r0, r5 +#endif +99: +	mov	#1, r6 +	mov	#0, r7 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD + +25: +#if cond_lock != 0 +	DEC (@(cond_lock,r8), r2) +#else +	DEC (@r8, r2) +#endif +	tst	r2, r2 +	bf	10f + +11: +	mov	r9, r4 +	mov.l	.Lmlocki1, r1 +	bsrf	r1 +	 nop +.Lmlocki1b: + +	/* We return the result of the mutex_lock operation if it failed.  */ +	tst	r0, r0 +	bf	18f +	mov.l	@(24,r15), r0 + +18: +	add	#64, r15 +	lds.l	@r15+, pr +	mov.l	@r15+, r13 +	mov.l	@r15+, r12 +	mov.l	@r15+, r11 +	mov.l	@r15+, r10 +	mov.l	@r15+, r9 +	rts +	 mov.l	@r15+, r8 + +#ifndef __ASSUME_PRIVATE_FUTEX +.Lpfoff: +	.word	PRIVATE_FUTEX - TLS_PRE_TCB_SIZE +#endif +.L1k: +	.word	1000 +	.align	2 +.Lmunlock1: +	.long	__pthread_mutex_unlock_usercnt-.Lmunlock1b +.Lenable1: +	.long	__pthread_enable_asynccancel-.Lenable1b +.Ldisable1: +	.long	__pthread_disable_asynccancel-.Ldisable1b +.Lmlocki1: +	.long	__pthread_mutex_cond_lock-.Lmlocki1b +.L1g: +	.long	1000000000 + +1: +	/* Initial locking failed.  */ +	mov	r8, r5 +#if cond_lock != 0 +	add	#cond_lock, r5 +#endif +	mov.l	@(dep_mutex,r8), r0 +	cmp/eq	#-1, r0 +	bf/s	99f +	 mov	#LLL_PRIVATE, r6 +	mov	#LLL_SHARED, r6 +99: +	extu.b	r6, r6 +	mov.l	.Lwait2, r1 +	bsrf	r1 +	 mov	r2, r4 +.Lwait2b: +	bra	2b +	 nop + +3: +	/* Unlock in loop requires wakeup.  */ +	mov	r8, r4 +#if cond_lock != 0 +	add	#cond_lock, r4 +#endif +	mov.l	@(dep_mutex,r8), r0 +	cmp/eq	#-1, r0 +	bf/s	99f +	 mov	#LLL_PRIVATE, r5 +	mov	#LLL_SHARED, r5 +99: +	mov.l	.Lmwait2, r1 +	bsrf	r1 +	 extu.b	r5, r5 +.Lmwait2b: +	bra	4b +	 nop + +5: +	/* Locking in loop failed.  */ +	mov	r8, r5 +#if cond_lock != 0 +	add	#cond_lock, r5 +#endif +	mov.l	@(dep_mutex,r8), r0 +	cmp/eq	#-1, r0 +	bf/s	99f +	 mov	#LLL_PRIVATE, r6 +	mov	#LLL_SHARED, r6 +99: +	extu.b	r6, r6 +	mov.l	.Lwait3, r1 +	bsrf	r1 +	 mov	r2, r4 +.Lwait3b: +	bra	6b +	 nop + +10: +	/* Unlock after loop requires wakeup.  */ +	mov	r8, r4 +#if cond_lock != 0 +	add	#cond_lock, r4 +#endif +	mov.l	@(dep_mutex,r8), r0 +	cmp/eq	#-1, r0 +	bf/s	99f +	 mov	#LLL_PRIVATE, r5 +	mov	#LLL_SHARED, r5 +99: +	mov.l	.Lmwait3, r1 +	bsrf	r1 +	 extu.b	r5, r5 +.Lmwait3b: +	bra	11b +	 nop + +16: +	/* The initial unlocking of the mutex failed.  */ +	mov.l	r0, @(24,r15) +#if cond_lock != 0 +	DEC (@(cond_lock,r8), r2) +#else +	DEC (@r8, r2) +#endif +	tst	r2, r2 +	bf	17f + +	mov	r8, r4 +#if cond_lock != 0 +	add	#cond_lock, r4 +#endif +	mov.l	@(dep_mutex,r8), r0 +	cmp/eq	#-1, r0 +	bf/s	99f +	 mov	#LLL_PRIVATE, r5 +	mov	#LLL_SHARED, r5 +99: +	mov.l	.Lmwait4, r1 +	bsrf	r1 +	 extu.b	r5, r5 +.Lmwait4b: +17: +	bra	18b +	 mov.l	@(24,r15), r0 + +	.align	2 +.Lwait2: +	.long	__lll_lock_wait-.Lwait2b +.Lmwait2: +	.long	__lll_unlock_wake-.Lmwait2b +.Lwait3: +	.long	__lll_lock_wait-.Lwait3b +.Lmwait3: +	.long	__lll_unlock_wake-.Lmwait3b +.Lmwait4: +	.long	__lll_unlock_wake-.Lmwait4b +	.size	__pthread_cond_timedwait, .-__pthread_cond_timedwait +weak_alias (__pthread_cond_timedwait, pthread_cond_timedwait) + + +	.type	__condvar_tw_cleanup, @function +__condvar_tw_cleanup: +	mov	r4, r11 + +	/* Get internal lock.  */ +	mov	#0, r3 +	mov	#1, r4 +#if cond_lock != 0 +	CMPXCHG (r3, @(cond_lock,r8), r4, r2) +#else +	CMPXCHG (r3, @r8, r4, r2) +#endif +	bt	1f +	 nop + +	mov	r8, r5 +#if cond_lock != 0 +	add	#cond_lock, r5 +#endif +	mov.l	@(dep_mutex,r8), r0 +	cmp/eq	#-1, r0 +	bf/s	99f +	 mov	#LLL_PRIVATE, r6 +	mov	#LLL_SHARED, r6 +99: +	extu.b	r6, r6 +	mov.l	.Lwait5, r1 +	bsrf	r1 +	 mov	r2, r4 +.Lwait5b: + +1: +	mov.l	@(broadcast_seq,r8), r0 +	mov.l	@(4,r15), r1 +	cmp/eq	r0, r1 +	bf	3f + +	mov	#1, r2 +	mov	#0, r3 + +	/* We increment the wakeup_seq counter only if it is lower than +	   total_seq.  If this is not the case the thread was woken and +	   then canceled.  In this case we ignore the signal.  */ +	mov.l	@(total_seq+4,r8), r0 +	mov.l	@(wakeup_seq+4,r8), r1 +	cmp/hi	r1, r0 +	bt/s	6f +	 cmp/hi	r0, r1 +	bt	7f +	mov.l	@(total_seq,r8), r0 +	mov.l	@(wakeup_seq,r8), r1 +	cmp/hs	r0, r1 +	bt	7f + +6: +	clrt +	mov.l	@(wakeup_seq,r8),r0 +	mov.l	@(wakeup_seq+4,r8),r1 +	addc	r2, r0 +	addc	r3, r1 +	mov.l	r0,@(wakeup_seq,r8) +	mov.l	r1,@(wakeup_seq+4,r8) +	mov.l	@(cond_futex,r8),r0 +	add	r2, r0 +	mov.l	r0,@(cond_futex,r8) + +7: +	clrt +	mov.l	@(woken_seq,r8),r0 +	mov.l	@(woken_seq+4,r8),r1 +	addc	r2, r0 +	addc	r3, r1 +	mov.l	r0,@(woken_seq,r8) +	mov.l	r1,@(woken_seq+4,r8) + +3: +	mov	#(1 << nwaiters_shift), r2 +	mov.l	@(cond_nwaiters,r8),r0 +	sub	r2, r0 +	mov.l	r0,@(cond_nwaiters,r8) + +	/* Wake up a thread which wants to destroy the condvar object.  */ +	mov	#0, r10 +	mov.l	@(total_seq,r8),r0 +	mov.l	@(total_seq+4,r8),r1 +	and	r1, r0 +	not	r0, r0 +	cmp/eq	#0, r0 +	bf/s	4f +	 mov	#((1 << nwaiters_shift) - 1), r1 +	not	r1, r1 +	mov.l	@(cond_nwaiters,r8),r0 +	tst	r1, r0 +	bf	4f + +	mov	r8, r4 +	add	#cond_nwaiters, r4 +	mov	#FUTEX_WAKE, r5 +	mov	#1, r6 +	mov	#0, r7 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD +	mov	#1, r10 + +4: +#if cond_lock != 0 +	DEC (@(cond_lock,r8), r2) +#else +	DEC (@r8, r2) +#endif +	tst	r2, r2 +	bt	2f + +	mov	r8, r4 +#if cond_lock != 0 +	add	#cond_lock, r4 +#endif +	mov.l	@(dep_mutex,r8), r0 +	cmp/eq	#-1, r0 +	bf/s	99f +	 mov	#LLL_PRIVATE, r5 +	mov	#LLL_SHARED, r5 +99: +	mov.l	.Lmwait5, r1 +	bsrf	r1 +	 extu.b	r5, r5 +.Lmwait5b: + +2: +	/* Wake up all waiters to make sure no signal gets lost.  */ +	tst	r10, r10 +	bf/s	5f +	 mov	r8, r4 +	add	#cond_futex, r4 +	mov	#FUTEX_WAKE, r5 +	mov	#-1, r6 +	shlr	r6		/* r6 = 0x7fffffff */ +	mov	#0, r7 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD + +5: +        mov.l   .Lmlocki5, r1 +        bsrf    r1 +         mov     r9, r4 +.Lmlocki5b: + +.LcallUR: +	mov.l	.Lresume, r1 +#ifdef __PIC__ +	add	r12, r1 +#endif +	jsr	@r1 +	 mov	r11, r4 +	sleep + +	.align	2 +.Lwait5: +	.long   __lll_lock_wait-.Lwait5b +.Lmwait5: +        .long   __lll_unlock_wake-.Lmwait5b +.Lmlocki5: +	.long   __pthread_mutex_cond_lock-.Lmlocki5b +.Lresume: +#ifdef __PIC__ +	.long	_Unwind_Resume@GOTOFF +#else +	.long	_Unwind_Resume +#endif +.LENDCODE: +	.size	__condvar_tw_cleanup, .-__condvar_tw_cleanup + + +	.section .gcc_except_table,"a",@progbits +.LexceptSTART: +	.byte	0xff				! @LPStart format (omit) +	.byte	0xff				! @TType format (omit) +	.byte	0x0b				! call-site format +						! DW_EH_PE_sdata4 +	.uleb128 .Lcstend-.Lcstbegin +.Lcstbegin: +	.ualong	.LcleanupSTART-.LSTARTCODE +	.ualong	.LcleanupEND-.LcleanupSTART +	.ualong	__condvar_tw_cleanup-.LSTARTCODE +	.uleb128  0 +	.ualong	.LcallUR-.LSTARTCODE +	.ualong	.LENDCODE-.LcallUR +	.ualong	0 +	.uleb128  0 +.Lcstend: + +	.section .eh_frame,"a",@progbits +.LSTARTFRAME: +	.ualong	.LENDCIE-.LSTARTCIE		! Length of the CIE. +.LSTARTCIE: +	.ualong	0				! CIE ID. +	.byte	1				! Version number. +#ifdef SHARED +	.string	"zPLR"				! NUL-terminated augmentation +						! string. +#else +	.string	"zPL"				! NUL-terminated augmentation +						! string. +#endif +	.uleb128 1				! Code alignment factor. +	.sleb128 -4				! Data alignment factor. +	.byte	0x11				! Return address register +						! column. +#ifdef SHARED +	.uleb128 7				! Augmentation value length. +	.byte	0x9b				! Personality: DW_EH_PE_pcrel +						! + DW_EH_PE_sdata4 +						! + DW_EH_PE_indirect +	.ualong	DW.ref.__gcc_personality_v0-. +	.byte	0x1b				! LSDA Encoding: DW_EH_PE_pcrel +						! + DW_EH_PE_sdata4. +	.byte	0x1b				! FDE Encoding: DW_EH_PE_pcrel +						! + DW_EH_PE_sdata4. +#else +	.uleb128 6				! Augmentation value length. +	.byte	0x0				! Personality: absolute +	.ualong	__gcc_personality_v0 +	.byte	0x0				! LSDA Encoding: absolute +#endif +	.byte 0x0c				! DW_CFA_def_cfa +	.uleb128 0xf +	.uleb128 0 +	.align 2 +.LENDCIE: + +	.ualong	.LENDFDE-.LSTARTFDE		! Length of the FDE. +.LSTARTFDE: +	.ualong	.LSTARTFDE-.LSTARTFRAME		! CIE pointer. +#ifdef SHARED +	.ualong	.LSTARTCODE-.			! PC-relative start address +						! of the code. +#else +	.ualong	.LSTARTCODE			! Start address of the code. +#endif +	.ualong	.LENDCODE-.LSTARTCODE		! Length of the code. +	.uleb128 4				! Augmentation size +#ifdef SHARED +	.ualong	.LexceptSTART-. +#else +	.ualong	.LexceptSTART +#endif +	.byte	0x4 +	.ualong	.Lpush_r8-.LSTARTCODE +	.byte	0xe +	.uleb128 4 +	.byte	0x88 +	.uleb128 1 +	.byte	0x4 +	.ualong	.Lpush_r9-.Lpush_r8 +	.byte	0xe +	.uleb128 8 +	.byte	0x89 +	.uleb128 2 +	.byte	0x4 +	.ualong	.Lpush_r10-.Lpush_r9 +	.byte	0xe +	.uleb128 12 +	.byte	0x8a +	.uleb128 3 +	.byte	0x4 +	.ualong	.Lpush_r11-.Lpush_r10 +	.byte	0xe +	.uleb128 16 +	.byte	0x8b +	.uleb128 4 +	.byte	0x4 +	.ualong	.Lpush_r12-.Lpush_r11 +	.byte	0xe +	.uleb128 20 +	.byte	0x8c +	.uleb128 5 +	.byte	0x4 +	.ualong	.Lpush_r13-.Lpush_r12 +	.byte	0xe +	.uleb128 24 +	.byte	0x8d +	.uleb128 6 +	.byte	0x4 +	.ualong	.Lpush_pr-.Lpush_r13 +	.byte	0xe +	.uleb128 28 +	.byte	0x91 +	.uleb128 7 +	.byte	0x4 +	.ualong	.Lalloc-.Lpush_pr +	.byte	0xe +	.uleb128 92 +	.align	2 +.LENDFDE: + +#ifdef SHARED +	.hidden DW.ref.__gcc_personality_v0 +	.weak   DW.ref.__gcc_personality_v0 +	.section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits +	.align 4 +	.type   DW.ref.__gcc_personality_v0, @object +	.size   DW.ref.__gcc_personality_v0, 4 +DW.ref.__gcc_personality_v0: +	.long   __gcc_personality_v0 +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S new file mode 100644 index 000000000..b0a4e9888 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S @@ -0,0 +1,754 @@ +/* Copyright (C) 2003, 2004, 2006, 2007 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelcond.h> +#include <tcb-offsets.h> +#include <bits/kernel-features.h> +#include "lowlevel-atomic.h" + +	.text + +/* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)  */ +	.globl	__pthread_cond_wait +	.type	__pthread_cond_wait, @function +	.protected	__pthread_cond_wait +	.align	5 +__pthread_cond_wait: +.LSTARTCODE: +	mov.l	r8, @-r15 +.Lpush_r8: +	mov.l	r9, @-r15 +.Lpush_r9: +	mov.l	r10, @-r15 +.Lpush_r10: +	mov.l	r11, @-r15 +.Lpush_r11: +	mov.l	r12, @-r15 +.Lpush_r12: +	sts.l	pr, @-r15 +.Lpush_pr: +	add	#-48, r15 +.Lalloc: +	mov	r4, r8 +	mov	r5, r9 +#ifdef __PIC__ +	mova	.Lgot0, r0 +	mov.l	.Lgot0, r12 +	add	r0, r12 +#endif + +	/* Get internal lock.  */ +	mov	#0, r3 +	mov	#1, r4 +#if cond_lock != 0 +	CMPXCHG (r3, @(cond_lock,r8), r4, r2) +#else +	CMPXCHG (r3, @r8, r4, r2) +#endif +	bt	2f +	bra	1f +	 nop +#ifdef __PIC__ +	.align	2 +.Lgot0: +	.long	_GLOBAL_OFFSET_TABLE_ +#endif + +2: +	/* Store the reference to the mutex.  If there is already a +	   different value in there this is a bad user bug.  */ +	mov.l	@(dep_mutex,r8),r0 +	cmp/eq	#-1, r0 +	bt	15f +	mov.l	r9, @(dep_mutex,r8) + +15: +	/* Unlock the mutex.  */ +	mov.l	.Lmunlock0, r1 +	mov	#0, r5 +	bsrf	r1 +	 mov	r9, r4 +.Lmunlock0b: + +	tst	r0, r0 +	bt	0f +	bra	12f +	 nop +0: +	mov	#1, r2 +	mov	#0, r3 + +	clrt +	mov.l	@(total_seq,r8),r0 +	mov.l	@(total_seq+4,r8),r1 +	addc	r2, r0 +	addc	r3, r1 +	mov.l	r0,@(total_seq,r8) +	mov.l	r1,@(total_seq+4,r8) +	mov.l	@(cond_futex,r8),r0 +	add	r2, r0 +	mov.l	r0,@(cond_futex,r8) +	mov	#(1 << nwaiters_shift), r2 +	mov.l	@(cond_nwaiters,r8), r0 +	add	r2, r0 +	mov.l	r0, @(cond_nwaiters,r8) + +	/* Get and store current wakeup_seq value.  */ +	mov.l	@(wakeup_seq,r8), r10 +	mov.l	@(wakeup_seq+4,r8), r11 +	mov.l	@(broadcast_seq,r8), r0 +	mov.l	r0, @(4,r15) + +8: +	mov.l	@(cond_futex,r8),r0 +	mov.l	r0, @(8,r15) + +	/* Unlock.  */ +#if cond_lock != 0 +	DEC (@(cond_lock,r8), r2) +#else +	DEC (@r8, r2) +#endif +	tst	r2, r2 +	bf	3f +4: +.LcleanupSTART: +	mov.l	.Lenable0, r1 +	bsrf	r1 +	 nop +.Lenable0b: +	mov.l	r0, @r15 + +	mov	#0, r7 +	mov.l	@(dep_mutex,r8), r0 +	cmp/eq	#-1, r0 +	bt/s	99f +	 mov	#FUTEX_WAIT, r5 +#ifdef __ASSUME_PRIVATE_FUTEX +	mov	#(FUTEX_WAIT|FUTEX_PRIVATE_FLAG), r5 +	extu.b	r5, r5 +#else +	stc	gbr, r1 +	mov.w	.Lpfoff0, r2 +	add	r2, r1 +	mov.l	@r1, r5 +	mov	#FUTEX_WAIT, r0 +	or	r0, r5 +#endif +99: +	mov.l	@(8,r15), r6 +	mov	r8, r4 +	add	#cond_futex, r4 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD + +	mov.l	.Ldisable0, r1 +	bsrf	r1 +	 mov.l	@r15, r4 +.Ldisable0b: +.LcleanupEND: + +	/* Lock.  */ +	mov	#0, r3 +	mov	#1, r4 +#if cond_lock != 0 +	CMPXCHG (r3, @(cond_lock,r8), r4, r2) +#else +	CMPXCHG (r3, @r8, r4, r2) +#endif +	bf	5f +6: +	mov.l	@(broadcast_seq,r8), r0 +	mov.l	@(4,r15), r1 +	cmp/eq	r0, r1 +	bf	16f + +	mov.l	@(woken_seq,r8), r0 +	mov.l	@(woken_seq+4,r8), r1 + +	mov.l	@(wakeup_seq,r8), r2 +	mov.l	@(wakeup_seq+4,r8), r3 + +	cmp/eq	r3, r11 +	bf	7f +	cmp/eq	r2, r10 +	bt	8b +7: +	cmp/eq	r1, r3 +	bf	9f +	cmp/eq	r0, r2 +	bt	8b +9: +	mov	#1, r2 +	mov	#0, r3 + +	clrt +	mov.l	@(woken_seq,r8),r0 +	mov.l	@(woken_seq+4,r8),r1 +	addc	r2, r0 +	addc	r3, r1 +	mov.l	r0,@(woken_seq,r8) +	mov.l	r1,@(woken_seq+4,r8) + +16: +	mov	#(1 << nwaiters_shift), r2 +	mov.l	@(cond_nwaiters,r8),r0 +	sub	r2, r0 +	mov.l	r0,@(cond_nwaiters,r8) + +	/* Wake up a thread which wants to destroy the condvar object.  */ +	mov.l	@(total_seq,r8),r0 +	mov.l	@(total_seq+4,r8),r1 +	and	r1, r0 +	not	r0, r0 +	cmp/eq	#0, r0 +	bf/s	17f +	 mov	#((1 << nwaiters_shift) - 1), r1 +	not	r1, r1 +	mov.l	@(cond_nwaiters,r8),r0 +	tst	r1, r0 +	bf	17f + +	mov	r8, r4 +	add	#cond_nwaiters, r4 +	mov.l	@(dep_mutex,r8), r0 +	cmp/eq	#-1, r0 +	bt/s	99f +	 mov	#FUTEX_WAKE, r5 +#ifdef __ASSUME_PRIVATE_FUTEX +	mov	#(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), r5 +	extu.b	r5, r5 +#else +	stc	gbr, r1 +	mov.w	.Lpfoff0, r2 +	add	r2, r1 +	mov.l	@r1, r5 +	mov	#FUTEX_WAKE, r0 +	or	r0, r5 +#endif +99: +	mov	#1, r6 +	mov	#0, r7 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD + +17: +#if cond_lock != 0 +	DEC (@(cond_lock,r8), r2) +#else +	DEC (@r8, r2) +#endif +	tst	r2, r2 +	bf	10f + +11: +	mov.l	.Lmlocki0, r1 +	bsrf	r1 +	 mov	r9, r4 +.Lmlocki0b: +	/* We return the result of the mutex_lock operation.  */ + +14: +	add	#48, r15 +	lds.l	@r15+, pr +	mov.l	@r15+, r12 +	mov.l	@r15+, r11 +	mov.l	@r15+, r10 +	mov.l	@r15+, r9 +	rts +	 mov.l	@r15+, r8 + +#ifndef __ASSUME_PRIVATE_FUTEX +.Lpfoff0: +	.word	PRIVATE_FUTEX - TLS_PRE_TCB_SIZE +#endif +	.align	2 +.Lmunlock0: +	.long	__pthread_mutex_unlock_usercnt-.Lmunlock0b +.Lenable0: +	.long	__pthread_enable_asynccancel-.Lenable0b +.Ldisable0: +	.long	__pthread_disable_asynccancel-.Ldisable0b +.Lmlocki0: +	.long	__pthread_mutex_cond_lock-.Lmlocki0b + +1: +	/* Initial locking failed.  */ +	mov	r8, r5 +#if cond_lock != 0 +	add	#cond_lock, r5 +#endif +	mov.l	@(dep_mutex,r8), r0 +	cmp/eq	#-1, r0 +	bf/s	99f +	 mov	#LLL_PRIVATE, r6 +	mov	#LLL_SHARED, r6 +99: +	extu.b	r6, r6 +	mov.l	.Lwait0, r1 +	bsrf	r1 +	 mov	r2, r4 +.Lwait0b: +	bra	2b +	 nop +3: +	/* Unlock in loop requires waekup.  */ +	mov	r8, r4 +#if cond_lock != 0 +	add	#cond_lock, r4 +#endif +	mov.l	@(dep_mutex,r8), r0 +	cmp/eq	#-1, r0 +	bf/s	99f +	 mov	#LLL_PRIVATE, r5 +	mov	#LLL_SHARED, r5 +99: +	mov.l	.Lwake0, r1 +	bsrf	r1 +	 extu.b	r5, r5 +.Lwake0b: +	bra	4b +	 nop + +5: +	/* Locking in loop failed.  */ +	mov	r8, r5 +#if cond_lock != 0 +	add	#cond_lock, r5 +#endif +	mov.l	@(dep_mutex,r8), r0 +	cmp/eq	#-1, r0 +	bf/s	99f +	 mov	#LLL_PRIVATE, r6 +	mov	#LLL_SHARED, r6 +99: +	extu.b	r6, r6 +	mov.l	.Lwait1, r1 +	bsrf	r1 +	 mov	r2, r4 +.Lwait1b: +	bra	6b +	 nop + +10: +	/* Unlock after loop requires wakeup.  */ +	mov	r8, r4 +#if cond_lock != 0 +	add	#cond_lock, r4 +#endif +	mov.l	@(dep_mutex,r8), r0 +	cmp/eq	#-1, r0 +	bf/s	99f +	 mov	#LLL_PRIVATE, r5 +	mov	#LLL_SHARED, r5 +99: +	mov.l	.Lwake1, r1 +	bsrf	r1 +	 extu.b	r5, r5 +.Lwake1b: +	bra	11b +	 nop + +12: +	/* The initial unlocking of the mutex failed.  */ +	mov.l	r0, @(12,r15) +#if cond_lock != 0 +	DEC (@(cond_lock,r8), r2) +#else +	DEC (@r8, r2) +#endif +	tst	r2, r2 +	bf	13f + +	mov	r8, r4 +#if cond_lock != 0 +	add	#cond_lock, r4 +#endif +	mov.l	@(dep_mutex,r8), r0 +	cmp/eq	#-1, r0 +	bf/s	99f +	 mov	#LLL_PRIVATE, r5 +	mov	#LLL_SHARED, r5 +99: +	mov.l	.Lwake2, r1 +	bsrf	r1 +	 extu.b	r5, r5 +.Lwake2b: + +13: +	bra	14b +	 mov.l	@(12,r15), r0 + +	.align	2 +.Lwait0: +	.long	__lll_lock_wait-.Lwait0b +.Lwake0: +	.long	__lll_unlock_wake-.Lwake0b +.Lwait1: +	.long	__lll_lock_wait-.Lwait1b +.Lwake1: +	.long	__lll_unlock_wake-.Lwake1b +.Lwake2: +	.long	__lll_unlock_wake-.Lwake2b +	.size	__pthread_cond_wait, .-__pthread_cond_wait +weak_alias (__pthread_cond_wait, pthread_cond_wait) + + +	.type	__condvar_w_cleanup, @function +__condvar_w_cleanup: +	mov	r4, r11 + +	/* Get internal lock.  */ +	mov	#0, r3 +	mov	#1, r4 +#if cond_lock != 0 +	CMPXCHG (r3, @(cond_lock,r8), r4, r2) +#else +	CMPXCHG (r3, @r8, r4, r2) +#endif +	bt	1f +	 nop + +	mov	r8, r5 +#if cond_lock != 0 +	add	#cond_lock, r5 +#endif +	mov.l	@(dep_mutex,r8), r0 +	cmp/eq	#-1, r0 +	bf/s	99f +	 mov	#LLL_PRIVATE, r6 +	mov	#LLL_SHARED, r6 +99: +	extu.b	r6, r6 +	mov.l	.Lwait3, r1 +	bsrf	r1 +	 mov	r2, r4 +.Lwait3b: + +1: +	mov.l	@(broadcast_seq,r8), r0 +	mov.l	@(4,r15), r1 +	cmp/eq	r0, r1 +	bf	3f + +	mov	#1, r2 +	mov	#0, r3 + +	/* We increment the wakeup_seq counter only if it is lower than +	   total_seq.  If this is not the case the thread was woken and +	   then canceled.  In this case we ignore the signal.  */ +	mov.l	@(total_seq+4,r8), r0 +	mov.l	@(wakeup_seq+4,r8), r1 +	cmp/hi	r1, r0 +	bt/s	6f +	 cmp/hi	r0, r1 +	bt	7f +	mov.l	@(total_seq,r8), r0 +	mov.l	@(wakeup_seq,r8), r1 +	cmp/hs	r0, r1 +	bt	7f + +6: +	clrt +	mov.l	@(wakeup_seq,r8),r0 +	mov.l	@(wakeup_seq+4,r8),r1 +	addc	r2, r0 +	addc	r3, r1 +	mov.l	r0,@(wakeup_seq,r8) +	mov.l	r1,@(wakeup_seq+4,r8) +	mov.l	@(cond_futex,r8),r0 +	add	r2, r0 +	mov.l	r0,@(cond_futex,r8) + +7: +	clrt +	mov.l	@(woken_seq,r8),r0 +	mov.l	@(woken_seq+4,r8),r1 +	addc	r2, r0 +	addc	r3, r1 +	mov.l	r0,@(woken_seq,r8) +	mov.l	r1,@(woken_seq+4,r8) + +3: +	mov	#(1 << nwaiters_shift), r2 +	mov.l	@(cond_nwaiters,r8),r0 +	sub	r2, r0 +	mov.l	r0,@(cond_nwaiters,r8) + +	/* Wake up a thread which wants to destroy the condvar object.  */ +	mov	#0, r10 +	mov.l	@(total_seq,r8),r0 +	mov.l	@(total_seq+4,r8),r1 +	and	r1, r0 +	not	r0, r0 +	cmp/eq	#0, r0 +	bf/s	4f +	 mov	#((1 << nwaiters_shift) - 1), r1 +	not	r1, r1 +	mov.l	@(cond_nwaiters,r8),r0 +	tst	r1, r0 +	bf	4f + +	mov	r8, r4 +	add	#cond_nwaiters, r4 +	mov.l	@(dep_mutex,r8), r0 +	cmp/eq	#-1, r0 +	bt/s	99f +	 mov	#FUTEX_WAKE, r5 +#ifdef __ASSUME_PRIVATE_FUTEX +	mov	#(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), r5 +	extu.b	r5, r5 +#else +	stc	gbr, r1 +	mov.w	.Lpfoff1, r2 +	add	r2, r1 +	mov.l	@r1, r5 +	mov	#FUTEX_WAKE, r0 +	or	r0, r5 +#endif +99: +	mov	#1, r6 +	mov	#0, r7 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD +	mov	#1, r10 + +4: +#if cond_lock != 0 +	DEC (@(cond_lock,r8), r2) +#else +	DEC (@r8, r2) +#endif +	tst	r2, r2 +	bt	2f + +	mov	r8, r4 +#if cond_lock != 0 +	add	#cond_lock, r4 +#endif +	mov.l	@(dep_mutex,r8), r0 +	cmp/eq	#-1, r0 +	bf/s	99f +	 mov	#LLL_PRIVATE, r5 +	mov	#LLL_SHARED, r5 +99: +	mov.l	.Lwake3, r1 +	bsrf	r1 +	 extu.b	r5, r5 +.Lwake3b: + +2: +	/* Wake up all waiters to make sure no signal gets lost.  */ +	tst	r10, r10 +	bf/s	5f +	 mov	r8, r4 +	add	#cond_futex, r4 +	mov.l	@(dep_mutex,r8), r0 +	cmp/eq	#-1, r0 +	bt/s	99f +	 mov	#FUTEX_WAKE, r5 +#ifdef __ASSUME_PRIVATE_FUTEX +	mov	#(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), r5 +	extu.b	r5, r5 +#else +	stc	gbr, r1 +	mov.w	.Lpfoff1, r2 +	add	r2, r1 +	mov.l	@r1, r5 +	mov	#FUTEX_WAKE, r0 +	or	r0, r5 +#endif +99: +	mov	#-1, r6 +	shlr	r6		/* r6 = 0x7fffffff */ +	mov	#0, r7 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD + +5: +        mov.l   .Lmlocki3, r1 +        bsrf    r1 +         mov     r9, r4 +.Lmlocki3b: + +.LcallUR: +	mov.l	.Lresume, r1 +#ifdef __PIC__ +	add	r12, r1 +#endif +	jsr	@r1 +	 mov	r11, r4 +	sleep + +#ifndef __ASSUME_PRIVATE_FUTEX +.Lpfoff1: +	.word	PRIVATE_FUTEX - TLS_PRE_TCB_SIZE +#endif +	.align	2 +.Lwait3: +	.long   __lll_lock_wait-.Lwait3b +.Lwake3: +        .long   __lll_unlock_wake-.Lwake3b +.Lmlocki3: +	.long   __pthread_mutex_cond_lock-.Lmlocki3b +.Lresume: +#ifdef __PIC__ +	.long	_Unwind_Resume@GOTOFF +#else +	.long	_Unwind_Resume +#endif +.LENDCODE: +	.size	__condvar_w_cleanup, .-__condvar_w_cleanup + + +	.section .gcc_except_table,"a",@progbits +.LexceptSTART: +	.byte	0xff				! @LPStart format (omit) +	.byte	0xff				! @TType format (omit) +	.byte	0x0b				! call-site format +						! DW_EH_PE_sdata4 +	.uleb128 .Lcstend-.Lcstbegin +.Lcstbegin: +	.ualong	.LcleanupSTART-.LSTARTCODE +	.ualong	.LcleanupEND-.LcleanupSTART +	.ualong	__condvar_w_cleanup-.LSTARTCODE +	.uleb128  0 +	.ualong	.LcallUR-.LSTARTCODE +	.ualong	.LENDCODE-.LcallUR +	.ualong	0 +	.uleb128  0 +.Lcstend: + +	.section .eh_frame,"a",@progbits +.LSTARTFRAME: +	.ualong	.LENDCIE-.LSTARTCIE		! Length of the CIE. +.LSTARTCIE: +	.ualong	0				! CIE ID. +	.byte	1				! Version number. +#ifdef SHARED +	.string	"zPLR"				! NUL-terminated augmentation +						! string. +#else +	.string	"zPL"				! NUL-terminated augmentation +						! string. +#endif +	.uleb128 1				! Code alignment factor. +	.sleb128 -4				! Data alignment factor. +	.byte	0x11				! Return address register +						! column. +#ifdef SHARED +	.uleb128 7				! Augmentation value length. +	.byte	0x9b				! Personality: DW_EH_PE_pcrel +						! + DW_EH_PE_sdata4 +						! + DW_EH_PE_indirect +	.ualong	DW.ref.__gcc_personality_v0-. +	.byte	0x1b				! LSDA Encoding: DW_EH_PE_pcrel +						! + DW_EH_PE_sdata4. +	.byte	0x1b				! FDE Encoding: DW_EH_PE_pcrel +						! + DW_EH_PE_sdata4. +#else +	.uleb128 6				! Augmentation value length. +	.byte	0x0				! Personality: absolute +	.ualong	__gcc_personality_v0 +	.byte	0x0				! LSDA Encoding: absolute +#endif +	.byte 0x0c				! DW_CFA_def_cfa +	.uleb128 0xf +	.uleb128 0 +	.align 2 +.LENDCIE: + +	.ualong	.LENDFDE-.LSTARTFDE		! Length of the FDE. +.LSTARTFDE: +	.ualong	.LSTARTFDE-.LSTARTFRAME		! CIE pointer. +#ifdef SHARED +	.ualong	.LSTARTCODE-.			! PC-relative start address +						! of the code. +#else +	.ualong	.LSTARTCODE			! Start address of the code. +#endif +	.ualong	.LENDCODE-.LSTARTCODE		! Length of the code. +	.uleb128 4				! Augmentation size +#ifdef SHARED +	.ualong	.LexceptSTART-. +#else +	.ualong	.LexceptSTART +#endif +	.byte	0x4 +	.ualong	.Lpush_r8-.LSTARTCODE +	.byte	0xe +	.uleb128 4 +	.byte	0x88 +	.uleb128 1 +	.byte	0x4 +	.ualong	.Lpush_r9-.Lpush_r8 +	.byte	0xe +	.uleb128 8 +	.byte	0x89 +	.uleb128 2 +	.byte	0x4 +	.ualong	.Lpush_r10-.Lpush_r9 +	.byte	0xe +	.uleb128 12 +	.byte	0x8a +	.uleb128 3 +	.byte	0x4 +	.ualong	.Lpush_r11-.Lpush_r10 +	.byte	0xe +	.uleb128 16 +	.byte	0x8b +	.uleb128 4 +	.byte	0x4 +	.ualong	.Lpush_r12-.Lpush_r11 +	.byte	0xe +	.uleb128 20 +	.byte	0x8c +	.uleb128 5 +	.byte	0x4 +	.ualong	.Lpush_pr-.Lpush_r12 +	.byte	0xe +	.uleb128 24 +	.byte	0x91 +	.uleb128 6 +	.byte	0x4 +	.ualong	.Lalloc-.Lpush_pr +	.byte	0xe +	.uleb128 72 +	.align	2 +.LENDFDE: + +#ifdef SHARED +	.hidden DW.ref.__gcc_personality_v0 +	.weak   DW.ref.__gcc_personality_v0 +	.section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits +	.align 4 +	.type   DW.ref.__gcc_personality_v0, @object +	.size   DW.ref.__gcc_personality_v0, 4 +DW.ref.__gcc_personality_v0: +	.long   __gcc_personality_v0 +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_once.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_once.S new file mode 100644 index 000000000..46234459a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_once.S @@ -0,0 +1,263 @@ +/* Copyright (C) 2003, 2004, 2007 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <unwindbuf.h> +#include <sysdep.h> +#include <bits/kernel-features.h> +#include <lowlevellock.h> +#include <tcb-offsets.h> +#include "lowlevel-atomic.h" + + +	.comm	__fork_generation, 4, 4 + +	.text +	.globl	__pthread_once +	.type	__pthread_once,@function +	.protected	__pthread_once +	.align	5 +	cfi_startproc +__pthread_once: +	mov.l	@r4, r0 +	tst	#2, r0 +	bt	1f +	rts +	 mov	#0, r0 + +1: +	mov.l	r12, @-r15 +	cfi_adjust_cfa_offset (4) +	cfi_rel_offset (r12, 0) +	mov.l	r9, @-r15 +	cfi_adjust_cfa_offset (4) +	cfi_rel_offset (r9, 0) +	mov.l	r8, @-r15 +	cfi_adjust_cfa_offset (4) +	cfi_rel_offset (r8, 0) +	sts.l	pr, @-r15 +	cfi_adjust_cfa_offset (4) +	cfi_rel_offset (pr, 0) +	mov	r5, r8 +	mov	r4, r9 + +	/* Not yet initialized or initialization in progress. +	   Get the fork generation counter now.  */ +6: +	mov.l	@r4, r1 +	mova	.Lgot, r0 +	mov.l	.Lgot, r12 +	add	r0, r12 + +5: +	mov	r1, r0 + +	tst	#2, r0 +	bf	4f + +	and	#3, r0 +	mov.l	.Lfgen, r2 +#ifdef __PIC__ +	add	r12, r2 +#endif +	mov.l	@r2, r3 +	or	r3, r0 +	or	#1, r0 +	mov	r0, r3 +	mov	r1, r5 + +	CMPXCHG (r5, @r4, r3, r2) +	bf	5b + +	/* Check whether another thread already runs the initializer.  */ +	mov	r2, r0 +	tst	#1, r0 +	bt	3f	/* No -> do it.  */ + +	/* Check whether the initializer execution was interrupted +	   by a fork.  */ +	xor	r3, r0 +	mov	#-4, r1	/* -4 = 0xfffffffc */ +	tst	r1, r0 +	bf	3f	/* Different for generation -> run initializer.  */ + +	/* Somebody else got here first.  Wait.  */ +#ifdef __ASSUME_PRIVATE_FUTEX +	mov	#(FUTEX_PRIVATE_FLAG|FUTEX_WAIT), r5 +	extu.b	r5, r5 +#else +	stc	gbr, r1 +	mov.w	.Lpfoff, r2 +	add	r2, r1 +	mov.l	@r1, r5 +# if FUTEX_WAIT != 0 +	mov	#FUTEX_WAIT, r0 +	or	r0, r5 +# endif +#endif +	mov	r3, r6 +	mov	#0, r7 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD +	bra	6b +	 nop + +	.align	2 +.Lgot: +	.long	_GLOBAL_OFFSET_TABLE_ +#ifdef __PIC__ +.Lfgen: +	.long	__fork_generation@GOTOFF +#else +.Lfgen: +	.long	__fork_generation +#endif + +3: +	/* Call the initializer function after setting up the +	   cancellation handler.  Note that it is not possible here +	   to use the unwind-based cleanup handling.  This would require +	   that the user-provided function and all the code it calls +	   is compiled with exceptions.  Unfortunately this cannot be +	   guaranteed.  */ +	add	#-UNWINDBUFSIZE, r15 +	cfi_adjust_cfa_offset (UNWINDBUFSIZE) + +	mov.l	.Lsigsetjmp, r1 +	mov	#UWJMPBUF, r4 +	add	r15, r4 +	bsrf	r1 +	 mov	#0, r5 +.Lsigsetjmp0: +	tst	r0, r0 +	bf	7f + +	mov.l	.Lcpush, r1 +	bsrf	r1 +	 mov	r15, r4 +.Lcpush0: + +	/* Call the user-provided initialization function.  */ +	jsr	@r8 +	 nop + +	/* Pop the cleanup handler.  */ +	mov.l	.Lcpop, r1 +	bsrf	r1 +	 mov	r15, r4 +.Lcpop0: + +	add	#UNWINDBUFSIZE, r15 +	cfi_adjust_cfa_offset (-UNWINDBUFSIZE) + +	/* Sucessful run of the initializer.  Signal that we are done.  */ +	INC (@r9, r2) +	/* Wake up all other threads.  */ +	mov	r9, r4 +#ifdef __ASSUME_PRIVATE_FUTEX +	mov	#(FUTEX_PRIVATE_FLAG|FUTEX_WAKE), r5 +	extu.b	r5, r5 +#else +	stc	gbr, r1 +	mov.w	.Lpfoff, r2 +	add	r2, r1 +	mov.l	@r1, r5 +	mov	#FUTEX_WAKE, r0 +	or	r0, r5 +#endif +	mov	#-1, r6 +	shlr	r6		/* r6 = 0x7fffffff */ +	mov	#0, r7 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD + +4: +	lds.l	@r15+, pr +	cfi_adjust_cfa_offset (-4) +	cfi_restore (pr) +	mov.l	@r15+, r8 +	cfi_adjust_cfa_offset (-4) +	cfi_restore (r8) +	mov.l	@r15+, r9 +	cfi_adjust_cfa_offset (-4) +	cfi_restore (r9) +	mov.l	@r15+, r12 +	cfi_adjust_cfa_offset (-4) +	cfi_restore (r12) +	rts +	 mov	#0, r0 + +7: +	/* __sigsetjmp returned for the second time.  */ +	cfi_adjust_cfa_offset (UNWINDBUFSIZE+16) +	cfi_offset (r12, -4) +	cfi_offset (r9, -8) +	cfi_offset (r8, -12) +	cfi_offset (pr, -16) +	mov	#0, r7 +	mov.l	r7, @r9 +	mov	r9, r4 +#ifdef __ASSUME_PRIVATE_FUTEX +	mov	#(FUTEX_PRIVATE_FLAG|FUTEX_WAKE), r5 +#else +	stc	gbr, r1 +	mov.w	.Lpfoff, r2 +	add	r2, r1 +	mov.l	@r1, r5 +	mov	#FUTEX_WAKE, r0 +	or	r0, r5 +#endif +	extu.b	r5, r5 +	mov	#-1, r6 +	shlr	r6		/* r6 = 0x7fffffff */ +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD + +	mov.l	.Lunext, r1 +	bsrf	r1 +	 mov	r15, r4 +.Lunext0: +	/* NOTREACHED */ +	sleep +	cfi_endproc + +#ifndef __ASSUME_PRIVATE_FUTEX +.Lpfoff: +	.word	PRIVATE_FUTEX - TLS_PRE_TCB_SIZE +#endif +	.align	2 +.Lsigsetjmp: +	.long	__sigsetjmp@PLT-(.Lsigsetjmp0-.) +.Lcpush: +	.long	HIDDEN_JUMPTARGET(__pthread_register_cancel)-.Lcpush0 +.Lcpop: +	.long	HIDDEN_JUMPTARGET(__pthread_unregister_cancel)-.Lcpop0 +.Lunext: +	.long	HIDDEN_JUMPTARGET(__pthread_unwind_next)-.Lunext0 +	.size	__pthread_once,.-__pthread_once + +	.globl	__pthread_once_internal +__pthread_once_internal = __pthread_once + +	.globl	pthread_once +pthread_once = __pthread_once diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S new file mode 100644 index 000000000..21e05e192 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S @@ -0,0 +1,255 @@ +/* Copyright (C) 2003, 2007 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include <bits/kernel-features.h> +#include "lowlevel-atomic.h" + + +	.text + +	.globl	__pthread_rwlock_rdlock +	.type	__pthread_rwlock_rdlock,@function +	.protected	__pthread_rwlock_rdlock +	.align	5 +__pthread_rwlock_rdlock: +	mov.l	r12, @-r15 +	mov.l	r9, @-r15 +	mov.l	r8, @-r15 +	sts.l	pr, @-r15 +	mov	r4, r8 + +	/* Get the lock.  */ +	mov	#0, r3 +	mov	#1, r4 +#if MUTEX == 0 +	CMPXCHG (r3, @r8, r4, r2) +#else +	CMPXCHG (r3, @(MUTEX,r8), r4, r2) +#endif +	bf	1f +2: +	mov.l	@(WRITER,r8), r0 +	tst	r0, r0 +	bf	14f +	mov.l	@(WRITERS_QUEUED,r8), r0 +	tst	r0, r0 +	bt	5f +	mov	#FLAGS, r0 +	mov.b	@(r0,r8), r0 +	tst	r0, r0 +	bt	5f +3: +	mov.l	@(READERS_QUEUED,r8), r0 +	add	#1, r0 +	mov.l	r0, @(READERS_QUEUED,r8) +	tst	r0, r0 +	bt	4f + +	mov.l	@(READERS_WAKEUP,r8), r9 + +#if MUTEX == 0 +	DEC (@r8, r2) +#else +	DEC (@(MUTEX,r8), r2) +#endif +	tst	r2, r2 +	bf	10f +11: +#ifdef __ASSUME_PRIVATE_FUTEX +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r5 +	mov	#(FUTEX_PRIVATE_FLAG|FUTEX_WAIT), r0 +	xor	r0, r5 +	extu.b	r5, r5 +#else +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r5 +	extu.b	r5, r5 +# if FUTEX_WAIT != 0 +	mov	#FUTEX_WAIT, r0 +	or	r0, r5 +# endif +	stc	gbr, r1 +	mov.w	.Lpfoff, r2 +	add	r2, r1 +	mov.l	@r1, r0 +	xor	r0, r5 +#endif +	mov	r8, r4 +	add	#READERS_WAKEUP, r4 +	mov	r9, r6 +	mov	#0, r7 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD + +	/* Reget the lock.  */ +	mov	#0, r3 +	mov	#1, r4 +#if MUTEX == 0 +	CMPXCHG (r3, @r8, r4, r2) +#else +	CMPXCHG (r3, @(MUTEX,r8), r4, r2) +#endif +	bf	12f +13: +	mov.l	@(READERS_QUEUED,r8), r0 +	add	#-1, r0 +	bra	2b +	 mov.l	r0, @(READERS_QUEUED,r8) + +5: +	mov	#0, r3 +	mov.l	@(NR_READERS,r8), r0 +	add	#1, r0 +	mov.l	r0, @(NR_READERS,r8) +	tst	r0, r0 +	bt	8f + +9: +#if MUTEX == 0 +	DEC (@r8, r2) +#else +	DEC (@(MUTEX,r8), r2) +#endif +	tst	r2, r2 +	bf	6f +7: +	lds.l	@r15+, pr +	mov.l	@r15+, r8 +	mov.l	@r15+, r9 +	mov.l	@r15+, r12 +	rts +	 mov	r3, r0 + +#ifndef __ASSUME_PRIVATE_FUTEX +.Lpfoff: +	.word	PRIVATE_FUTEX - TLS_PRE_TCB_SIZE +#endif + +1: +	mov	r8, r5 +#if MUTEX != 0 +	add	#MUTEX, r5 +#endif +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r6 +	extu.b	r6, r6 +	mov.l	.Lwait0, r1 +	bsrf	r1 +	 mov	r2, r4 +.Lwait0b: +	bra	2b +	 nop +14: +	stc	gbr, r1 +	mov.w	.Ltidoff, r2 +	add	r2, r1 +	mov.l	@r1, r1 +	cmp/eq	r1, r0 +	bf	3b +	/* Deadlock detected.  */ +	bra	9b +	 mov	#EDEADLK, r3 + +.Ltidoff: +	.word	TID - TLS_PRE_TCB_SIZE + +6: +	mov	r8, r4 +#if MUTEX != 0 +	add	#MUTEX, r4 +#endif +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r5 +	extu.b	r5, r5 +	mov.l	.Lwake0, r1 +	bsrf	r1 +	 nop +.Lwake0b: +	bra	7b +	 mov	#0, r3 + +8: +	/* Overflow.  */ +	mov.l	@(NR_READERS,r8), r1 +	add	#-1, r1 +	mov.l	r1, @(NR_READERS,r8) +	bra	9b +	 mov	#EAGAIN, r3 + +4: +	/* Overflow.  */ +	mov.l	@(READERS_QUEUED,r8), r1 +	add	#-1, r1 +	mov.l	r1, @(READERS_QUEUED,r8) +	bra	9b +	 mov	#EAGAIN, r3 + +10: +	mov	r8, r4 +#if MUTEX != 0 +	add	#MUTEX, r4 +#endif +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r5 +	extu.b	r5, r5 +	mov.l	.Lwake1, r1 +	bsrf	r1 +	 nop +.Lwake1b: +	bra	11b +	 nop + +12: +	mov	r8, r5 +#if MUTEX != 0 +	add	#MUTEX, r5 +#endif +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r6 +	extu.b	r6, r6 +	mov.l	.Lwait1, r1 +	bsrf	r1 +	 mov	r2, r4 +.Lwait1b: +	bra	13b +	 nop + +	.align	2 +.Lwait0: +	.long	__lll_lock_wait-.Lwait0b +.Lwake0: +	.long	__lll_unlock_wake-.Lwake0b +.Lwait1: +	.long	__lll_lock_wait-.Lwait1b +.Lwake1: +	.long	__lll_unlock_wake-.Lwake1b +	.size	__pthread_rwlock_rdlock,.-__pthread_rwlock_rdlock + +	.globl	pthread_rwlock_rdlock +pthread_rwlock_rdlock = __pthread_rwlock_rdlock + +	.globl	__pthread_rwlock_rdlock_internal +__pthread_rwlock_rdlock_internal = __pthread_rwlock_rdlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S new file mode 100644 index 000000000..6e7af21e9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S @@ -0,0 +1,314 @@ +/* Copyright (C) 2003, 2007, 2008 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include <bits/kernel-features.h> +#include "lowlevel-atomic.h" + + +	.text + +	.globl	pthread_rwlock_timedrdlock +	.type	pthread_rwlock_timedrdlock,@function +	.align	5 +pthread_rwlock_timedrdlock: +	mov.l	r12, @-r15 +	mov.l	r10, @-r15 +	mov.l	r9, @-r15 +	mov.l	r8, @-r15 +	sts.l	pr, @-r15 +	add	#-8, r15 +	mov	r4, r8 +	mov	r5, r9 + +	/* Get the lock.  */ +	mov	#0, r3 +	mov	#1, r4 +#if MUTEX == 0 +	CMPXCHG (r3, @r8, r4, r2) +#else +	CMPXCHG (r3, @(MUTEX,r8), r4, r2) +#endif +	bf	1f +2: +	mov.l	@(WRITER,r8), r0 +	tst	r0, r0 +	bf	14f +	mov.l	@(WRITERS_QUEUED,r8), r0 +	tst	r0, r0 +	bt	5f +	mov	#FLAGS, r0 +	mov.b	@(r0,r8), r0 +	tst	r0, r0 +	bt	5f +3: +	/* Check the value of the timeout parameter.  */ +	mov.l	.L1g0, r1 +	mov.l	@(4,r9), r0 +	cmp/hs	r1, r0 +	bt	19f + +	mov.l	@(READERS_QUEUED,r8), r0 +	add	#1, r0 +	mov.l	r0, @(READERS_QUEUED,r8) +	tst	r0, r0 +	bt	4f + +	mov.l	@(READERS_WAKEUP,r8), r10 + +#if MUTEX == 0 +	DEC (@r8, r2) +#else +	DEC (@(MUTEX,r8), r2) +#endif +	tst	r2, r2 +	bf	10f + +11: +	/* Get current time.  */ +	mov	r15, r4 +	mov	#0, r5 +	mov	#__NR_gettimeofday, r3 +	trapa	#0x12 +	SYSCALL_INST_PAD + +	mov.l	@(4,r15), r0 +	mov.w	.L1k0, r1 +	dmulu.l	r0, r1		/* Milli seconds to nano seconds.  */ +	mov.l	@r9, r2 +	mov.l	@(4,r9), r3 +	mov.l	@r15, r0 +	sts	macl, r1 +	sub	r0, r2 +	clrt +	subc	r1, r3 +	bf	15f +	mov.l	.L1g0, r1 +	add	r1, r3 +	add	#-1, r2 +15: +	cmp/pz	r2 +	bf	16f		/* Time is already up.  */ + +	/* Store relative timeout.  */ +	mov.l	r2, @r15 +	mov.l	r3, @(4,r15) + +	/* Futex call.  */ +	mov	r15, r7 +#ifdef __ASSUME_PRIVATE_FUTEX +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r5 +	mov	#(FUTEX_PRIVATE_FLAG|FUTEX_WAIT), r0 +	xor	r0, r5 +	extu.b	r5, r5 +#else +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r5 +	extu.b	r5, r5 +# if FUTEX_WAIT != 0 +	mov	#FUTEX_WAIT, r0 +	or	r0, r5 +# endif +	stc	gbr, r1 +	mov.w	.Lpfoff, r2 +	add	r2, r1 +	mov.l	@r1, r0 +	xor	r0, r5 +#endif +	mov	r10, r6 +	mov	r8, r4 +	add	#READERS_WAKEUP, r4 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD +	mov	r0, r3 + +17: +	/* Reget the lock.  */ +	mov	#0, r5 +	mov	#1, r4 +#if MUTEX == 0 +	CMPXCHG (r5, @r8, r4, r2) +#else +	CMPXCHG (r5, @(MUTEX,r8), r4, r2) +#endif +	bf	12f + +13: +	mov.l	@(READERS_QUEUED,r8), r0 +	add	#-1, r0 +	mov.l	r0, @(READERS_QUEUED,r8) +	mov	#-ETIMEDOUT, r0 +	cmp/eq	r0, r3 +	bf	2b + +18: +	bra	9f +	 mov	#ETIMEDOUT, r3 + +5: +	mov	#0, r3 +	mov.l	@(NR_READERS,r8), r0 +	add	#1, r0 +	mov.l	r0, @(NR_READERS,r8) +	tst	r0, r0 +	bt	8f + +9: +#if MUTEX == 0 +	DEC (@r8, r2) +#else +	DEC (@(MUTEX,r8), r2) +#endif +	tst	r2, r2 +	bf	6f +7: +	add	#8,r15 +	lds.l	@r15+, pr +	mov.l	@r15+, r8 +	mov.l	@r15+, r9 +	mov.l	@r15+, r10 +	mov.l	@r15+, r12 +	rts +	 mov	r3, r0 + +#ifndef __ASSUME_PRIVATE_FUTEX +.Lpfoff: +	.word	PRIVATE_FUTEX - TLS_PRE_TCB_SIZE +#endif +	.align	2 +.L1k0: +	.long	1000 +.L1g0: +	.long	1000000000 + +1: +	mov	r8, r5 +#if MUTEX != 0 +	add	#MUTEX, r5 +#endif +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r6 +	extu.b	r6, r6 +	mov.l	.Lwait2, r1 +	bsrf	r1 +	 mov	r2, r4 +.Lwait2b: +	bra	2b +	 nop +14: +	stc	gbr, r1 +	mov.w	.Ltidoff, r2 +	add	r2, r1 +	mov.l	@r1, r1 +	cmp/eq	r1, r0 +	bf	3b +	/* Deadlock detected.  */ +	bra	9b +	 mov	#EDEADLK, r3 + +.Ltidoff: +	.word	TID - TLS_PRE_TCB_SIZE + +6: +	mov	r3, r10 +	mov	r8, r4 +#if MUTEX != 0 +	add	#MUTEX, r4 +#endif +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r5 +	extu.b	r5, r5 +	mov.l	.Lwake2, r1 +	bsrf	r1 +	 nop +.Lwake2b: +	bra	7b +	 mov	r10, r3 + +8: +	/* Overflow.  */ +	mov.l	@(NR_READERS,r8), r1 +	add	#-1, r1 +	mov.l	r1, @(NR_READERS,r8) +	bra	9b +	 mov	#EAGAIN, r3 + +4: +	/* Overflow.  */ +	mov.l	@(READERS_QUEUED,r8), r1 +	add	#-1, r1 +	mov.l	r1, @(READERS_QUEUED,r8) +	bra	9b +	 mov	#EAGAIN, r3 + +10: +	mov	r8, r4 +#if MUTEX != 0 +	add	#MUTEX, r4 +#endif +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r5 +	extu.b	r5, r5 +	mov.l	.Lwake3, r1 +	bsrf	r1 +	 nop +.Lwake3b: +	bra	11b +	 nop + +12: +	mov	r3, r10 +	mov	r8, r5 +#if MUTEX != 0 +	add	#MUTEX, r5 +#endif +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r6 +	extu.b	r6, r6 +	mov.l	.Lwait3, r1 +	bsrf	r1 +	 mov	r2, r4 +.Lwait3b: +	bra	13b +	 mov	r10, r3 + +16: +	bra	17b +	 mov	#-ETIMEDOUT, r3 + +19: +	bra	9b +	 mov	#EINVAL, r3 + +	.align	2 +.Lwait2: +	.long	__lll_lock_wait-.Lwait2b +.Lwake2: +	.long	__lll_unlock_wake-.Lwake2b +.Lwait3: +	.long	__lll_lock_wait-.Lwait3b +.Lwake3: +	.long	__lll_unlock_wake-.Lwake3b +	.size	pthread_rwlock_timedrdlock,.-pthread_rwlock_timedrdlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S new file mode 100644 index 000000000..1cb7cbdde --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S @@ -0,0 +1,298 @@ +/* Copyright (C) 2003, 2007, 2008 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include <bits/kernel-features.h> +#include "lowlevel-atomic.h" + + +	.text + +	.globl	pthread_rwlock_timedwrlock +	.type	pthread_rwlock_timedwrlock,@function +	.align	5 +pthread_rwlock_timedwrlock: +	mov.l	r12, @-r15 +	mov.l	r10, @-r15 +	mov.l	r9, @-r15 +	mov.l	r8, @-r15 +	sts.l	pr, @-r15 +	add	#-8, r15 +	mov	r4, r8 +	mov	r5, r9 + +	/* Get the lock.  */ +	mov	#0, r3 +	mov	#1, r4 +#if MUTEX == 0 +	CMPXCHG (r3, @r8, r4, r2) +#else +	CMPXCHG (r3, @(MUTEX,r8), r4, r2) +#endif +	bf	1f +2: +	mov.l	@(WRITER,r8), r0 +	tst	r0, r0 +	bf	14f +	mov.l	@(NR_READERS,r8), r0 +	tst	r0, r0 +	bt	5f +3: +	/* Check the value of the timeout parameter.  */ +	mov.l	.L1g1, r1 +	mov.l	@(4,r9), r0 +	cmp/hs	r1, r0 +	bt	19f + +	mov.l	@(WRITERS_QUEUED,r8), r0 +	add	#1, r0 +	mov.l	r0, @(WRITERS_QUEUED,r8) +	tst	r0, r0 +	bt	4f + +	mov.l	@(WRITERS_WAKEUP,r8), r10 + +#if MUTEX == 0 +	DEC (@r8, r2) +#else +	DEC (@(MUTEX,r8), r2) +#endif +	tst	r2, r2 +	bf	10f + +11: +	/* Get current time.  */ +	mov	r15, r4 +	mov	#0, r5 +	mov	#__NR_gettimeofday, r3 +	trapa	#0x12 +	SYSCALL_INST_PAD + +	mov.l	@(4,r15), r0 +	mov.w	.L1k1, r1 +	dmulu.l	r0, r1		/* Milli seconds to nano seconds.  */ +	mov.l	@r9, r2 +	mov.l	@(4,r9), r3 +	mov.l	@r15, r0 +	sts	macl, r1 +	sub	r0, r2 +	clrt +	subc	r1, r3 +	bf	15f +	mov.l	.L1g1, r1 +	add	r1, r3 +	add	#-1, r2 +15: +	cmp/pz	r2 +	bf	16f		/* Time is already up.  */ + +	/* Store relative timeout.  */ +	mov.l	r2, @r15 +	mov.l	r3, @(4,r15) + +	/* Futex call.  */ +	mov	r15, r7 +#ifdef __ASSUME_PRIVATE_FUTEX +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r5 +	mov	#(FUTEX_PRIVATE_FLAG|FUTEX_WAIT), r0 +	xor	r0, r5 +	extu.b	r5, r5 +#else +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r5 +	extu.b	r5, r5 +# if FUTEX_WAIT != 0 +	mov	#FUTEX_WAIT, r0 +	or	r0, r5 +# endif +	stc	gbr, r1 +	mov.w	.Lpfoff, r2 +	add	r2, r1 +	mov.l	@r1, r0 +	xor	r0, r5 +#endif +	mov	r10, r6 +	mov	r8, r4 +	add	#WRITERS_WAKEUP, r4 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD +	mov	r0, r3 + +17: +	/* Reget the lock.  */ +	mov	#0, r5 +	mov	#1, r4 +#if MUTEX == 0 +	CMPXCHG (r5, @r8, r4, r2) +#else +	CMPXCHG (r5, @(MUTEX,r8), r4, r2) +#endif +	bf	12f + +13: +	mov.l	@(WRITERS_QUEUED,r8), r0 +	add	#-1, r0 +	mov.l	r0, @(WRITERS_QUEUED,r8) +	mov	#-ETIMEDOUT, r0 +	cmp/eq	r0, r3 +	bf	2b + +18: +	bra	9f +	 mov	#ETIMEDOUT, r3 + +19: +	bra	9f +	 mov	#EINVAL, r3 + +5: +	mov	#0, r3 +	stc	gbr, r0 +	mov.w	.Ltidoff, r1 +	mov.l	@(r0,r1), r0 +	mov.l	r0, @(WRITER,r8) +9: +#if MUTEX == 0 +	DEC (@r8, r2) +#else +	DEC (@(MUTEX,r8), r2) +#endif +	tst	r2, r2 +	bf	6f +7: +	add	#8,r15 +	lds.l	@r15+, pr +	mov.l	@r15+, r8 +	mov.l	@r15+, r9 +	mov.l	@r15+, r10 +	mov.l	@r15+, r12 +	rts +	 mov	r3, r0 + +#ifndef __ASSUME_PRIVATE_FUTEX +.Lpfoff: +	.word	PRIVATE_FUTEX - TLS_PRE_TCB_SIZE +#endif +.L1k1: +	.word	1000 +	.align	2 +.L1g1: +	.long	1000000000 + +1: +	mov	r8, r5 +#if MUTEX != 0 +	add	#MUTEX, r5 +#endif +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r6 +	extu.b	r6, r6 +	mov.l	.Lwait6, r1 +	bsrf	r1 +	 mov	r2, r4 +.Lwait6b: +	bra	2b +	 nop +14: +	stc	gbr, r1 +	mov.w	.Ltidoff, r2 +	add	r2, r1 +	mov.l	@r1, r1 +	cmp/eq	r1, r0 +	bf	3b +	bra	9b +	 mov	#EDEADLK, r3 +6: +	mov	r3, r10 +	mov	r8, r4 +#if MUTEX != 0 +	add	#MUTEX, r4 +#endif +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r5 +	extu.b	r5, r5 +	mov.l	.Lwake6, r1 +	bsrf	r1 +	 nop +.Lwake6b: +	bra	7b +	 mov	r10, r3 + +.Ltidoff: +	.word	TID - TLS_PRE_TCB_SIZE + +4: +	/* Overflow.  */ +	mov.l	@(WRITERS_QUEUED,r8), r1 +	add	#-1, r1 +	mov.l	r1, @(WRITERS_QUEUED,r8) +	bra	9b +	 mov	#EAGAIN, r3 + +10: +	mov	r8, r4 +#if MUTEX != 0 +	add	#MUTEX, r4 +#endif +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r5 +	extu.b	r5, r5 +	mov.l	.Lwake7, r1 +	bsrf	r1 +	 nop +.Lwake7b: +	bra	11b +	 nop + +12: +	mov	r3, r10 +	mov	r8, r5 +#if MUTEX != 0 +	add	#MUTEX, r5 +#endif +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r6 +	extu.b	r6, r6 +	mov.l	.Lwait7, r1 +	bsrf	r1 +	 mov	r2, r4 +.Lwait7b: +	bra	13b +	 mov	r10, r3 + +16: +	bra	17b +	 mov	#-ETIMEDOUT, r3 + +	.align	2 +.Lwait6: +	.long	__lll_lock_wait-.Lwait6b +.Lwake6: +	.long	__lll_unlock_wake-.Lwake6b +.Lwait7: +	.long	__lll_lock_wait-.Lwait7b +.Lwake7: +	.long	__lll_unlock_wake-.Lwake7b +	.size	pthread_rwlock_timedwrlock,.-pthread_rwlock_timedwrlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S new file mode 100644 index 000000000..1f6c1d812 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S @@ -0,0 +1,199 @@ +/* Copyright (C) 2003, 2007 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelrwlock.h> +#include <bits/kernel-features.h> +#include <tcb-offsets.h> +#include "lowlevel-atomic.h" + + +	.text + +	.globl	__pthread_rwlock_unlock +	.type	__pthread_rwlock_unlock,@function +	.protected	__pthread_rwlock_unlock +	.align	5 +__pthread_rwlock_unlock: +	mov.l	r12, @-r15 +	mov.l	r8, @-r15 +	sts.l	pr, @-r15 +	mov	r4, r8 + +	/* Get the lock.  */ +	mov	#0, r3 +	mov	#1, r4 +#if MUTEX == 0 +	CMPXCHG (r3, @r8, r4, r2) +#else +	CMPXCHG (r3, @(MUTEX,r8), r4, r2) +#endif +	bf	1f +2: +	mov.l	@(WRITER,r8), r0 +	tst	r0, r0 +	bf	5f +	mov.l	@(NR_READERS,r8), r0 +	add	#-1, r0 +	mov.l	r0, @(NR_READERS,r8) +	tst	r0, r0 +	bf	6f +5: +	mov	#0, r0 +	mov.l	r0, @(WRITER,r8) +	mov	#1, r6 +	mov	r8, r4 +	add	#WRITERS_WAKEUP, r4 +	mov.l	@(WRITERS_QUEUED,r8), r0 +	tst	r0, r0 +	bf	0f + +	/* If also no readers waiting nothing to do.  */ +	mov.l	@(READERS_QUEUED,r8), r0 +	tst	r0, r0 +	bt	6f + +	mov	#-1, r6 +	shlr	r6		/* r6 = 0x7fffffff */ +	mov	r8, r4 +	add	#READERS_WAKEUP, r4 + +0: +	mov.l	@r4, r0 +	add	#1, r0 +	mov.l	r0, @r4 +#if MUTEX == 0 +	DEC (@r8, r2) +#else +	DEC (@(MUTEX,r8), r2) +#endif +	tst	r2, r2 +	bf	7f + +8: +#ifdef __ASSUME_PRIVATE_FUTEX +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r5 +	mov	#(FUTEX_PRIVATE_FLAG|FUTEX_WAKE), r0 +	xor	r0, r5 +	extu.b	r5, r5 +#else +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r5 +	extu.b	r5, r5 +	mov	#FUTEX_WAKE, r0 +	or	r0, r5 +	stc	gbr, r1 +	mov.w	.Lpfoff, r2 +	add	r2, r1 +	mov.l	@r1, r0 +	xor	r0, r5 +#endif +	mov	#SYS_futex, r3 +	mov	#0, r7 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD + +	lds.l	@r15+, pr +	mov.l	@r15+, r8 +	mov.l	@r15+, r12 +	rts +	 mov	#0, r0 +6: +#if MUTEX == 0 +	DEC (@r8, r2) +#else +	DEC (@(MUTEX,r8), r2) +#endif +	tst	r2, r2 +	bf	3f +4: +	lds.l	@r15+, pr +	mov.l	@r15+, r8 +	mov.l	@r15+, r12 +	rts +	 mov	#0, r0 + +1: +	mov	r8, r5 +#if MUTEX != 0 +	add	#MUTEX, r5 +#endif +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r6 +	extu.b	r6, r6 +	mov.l	.Lwait8, r1 +	bsrf	r1 +	 mov	r2, r4 +.Lwait8b: +	bra	2b +	 nop +3: +	mov	r8, r4 +#if MUTEX != 0 +	add	#MUTEX, r4 +#endif +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r5 +	extu.b	r5, r5 +	mov.l	.Lwake8, r1 +	bsrf	r1 +	 nop +.Lwake8b: +	bra	4b +	 nop + +7: +	mov.l	r4, @-r15 +	mov.l	r6, @-r15 +	mov	r8, r4 +#if MUTEX != 0 +	add	#MUTEX, r4 +#endif +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r5 +	extu.b	r5, r5 +	mov.l	.Lwake9, r1 +	bsrf	r1 +	 nop +.Lwake9b: + +	mov.l	@r15+, r6 +	bra	8b +	 mov.l	@r15+, r4 + +#ifndef __ASSUME_PRIVATE_FUTEX +.Lpfoff: +	.word	PRIVATE_FUTEX - TLS_PRE_TCB_SIZE +#endif +	.align	2 +.Lwait8: +	.long	__lll_lock_wait-.Lwait8b +.Lwake8: +	.long	__lll_unlock_wake-.Lwake8b +.Lwake9: +	.long	__lll_unlock_wake-.Lwake9b +	.size	__pthread_rwlock_unlock,.-__pthread_rwlock_unlock + +	.globl	pthread_rwlock_unlock +pthread_rwlock_unlock = __pthread_rwlock_unlock + +	.globl	__pthread_rwlock_unlock_internal +__pthread_rwlock_unlock_internal = __pthread_rwlock_unlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S new file mode 100644 index 000000000..e7bfe0d09 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S @@ -0,0 +1,235 @@ +/* Copyright (C) 2003, 2007 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include <bits/kernel-features.h> +#include "lowlevel-atomic.h" + + +	.text + +	.globl	__pthread_rwlock_wrlock +	.type	__pthread_rwlock_wrlock,@function +	.protected	__pthread_rwlock_wrlock +	.align	5 +__pthread_rwlock_wrlock: +	mov.l	r12, @-r15 +	mov.l	r9, @-r15 +	mov.l	r8, @-r15 +	sts.l	pr, @-r15 +	mov	r4, r8 + +	/* Get the lock.  */ +	mov	#0, r3 +	mov	#1, r4 +#if MUTEX == 0 +	CMPXCHG (r3, @r8, r4, r2) +#else +	CMPXCHG (r3, @(MUTEX,r8), r4, r2) +#endif +	bf	1f +2: +	mov.l	@(WRITER,r8), r0 +	tst	r0, r0 +	bf	14f +	mov.l	@(NR_READERS,r8), r0 +	tst	r0, r0 +	bt	5f +3: +	mov.l	@(WRITERS_QUEUED,r8), r0 +	add	#1, r0 +	mov.l	r0, @(WRITERS_QUEUED,r8) +	tst	r0, r0 +	bt	4f + +	mov.l	@(WRITERS_WAKEUP,r8), r9 + +#if MUTEX == 0 +	DEC (@r8, r2) +#else +	DEC (@(MUTEX,r8), r2) +#endif +	tst	r2, r2 +	bf	10f +11: +	mov	r8, r4 +	add	#WRITERS_WAKEUP, r4 +#ifdef __ASSUME_PRIVATE_FUTEX +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r5 +	mov	#(FUTEX_PRIVATE_FLAG|FUTEX_WAIT), r0 +	xor	r0, r5 +	extu.b	r5, r5 +#else +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r5 +	extu.b	r5, r5 +# if FUTEX_WAIT != 0 +	mov	#FUTEX_WAIT, r0 +	or	r0, r5 +# endif +	stc	gbr, r1 +	mov.w	.Lpfoff, r2 +	add	r2, r1 +	mov.l	@r1, r0 +	xor	r0, r5 +#endif +	mov	r9, r6 +	mov	#0, r7 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD + +	/* Reget the lock.  */ +	mov	#0, r3 +	mov	#1, r4 +#if MUTEX == 0 +	CMPXCHG (r3, @r8, r4, r2) +#else +	CMPXCHG (r3, @(MUTEX,r8), r4, r2) +#endif +	bf	12f +13: +	mov.l	@(WRITERS_QUEUED,r8), r0 +	add	#-1, r0 +	bra	2b +	 mov.l	r0, @(WRITERS_QUEUED,r8) + +5: +	mov	#0, r3 +	stc	gbr, r0 +	mov.w	.Ltidoff, r1 +	mov.l	@(r0,r1), r0 +	mov.l	r0, @(WRITER,r8) +9: +#if MUTEX == 0 +	DEC (@r8, r2) +#else +	DEC (@(MUTEX,r8), r2) +#endif +	tst	r2, r2 +	bf	6f +7: +	lds.l	@r15+, pr +	mov.l	@r15+, r8 +	mov.l	@r15+, r9 +	mov.l	@r15+, r12 +	rts +	 mov	r3, r0 + +1: +	mov	r8, r5 +#if MUTEX != 0 +	add	#MUTEX, r5 +#endif +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r6 +	extu.b	r6, r6 +	mov.l	.Lwait4, r1 +	bsrf	r1 +	 mov	r2, r4 +.Lwait4b: +	bra	2b +	 nop +14: +	stc	gbr, r1 +	mov.w	.Ltidoff, r2 +	add	r2, r1 +	mov.l	@r1, r1 +	cmp/eq	r1, r0 +	bf	3b +	bra	9b +	 mov	#EDEADLK, r3 +6: +	mov	r8, r4 +#if MUTEX != 0 +	add	#MUTEX, r4 +#endif +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r5 +	extu.b	r5, r5 +	mov.l	.Lwake4, r1 +	bsrf	r1 +	 nop +.Lwake4b: +	bra	7b +	 mov	#0, r3 + +#ifndef __ASSUME_PRIVATE_FUTEX +.Lpfoff: +	.word	PRIVATE_FUTEX - TLS_PRE_TCB_SIZE +#endif +.Ltidoff: +	.word	TID - TLS_PRE_TCB_SIZE + +4: +	mov.l	@(WRITERS_QUEUED,r8), r1 +	add	#-1, r1 +	mov.l	r1, @(WRITERS_QUEUED,r8) +	bra	9b +	 mov	#EAGAIN, r3 + +10: +	mov	r8, r4 +#if MUTEX != 0 +	add	#MUTEX, r4 +#endif +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r5 +	extu.b	r5, r5 +	mov.l	.Lwake5, r1 +	bsrf	r1 +	 nop +.Lwake5b: +	bra	11b +	 nop + +12: +	mov	r8, r5 +#if MUTEX != 0 +	add	#MUTEX, r5 +#endif +	mov	#PSHARED, r0 +	mov.b	@(r0,r8), r6 +	extu.b	r6, r6 +	mov.l	.Lwait5, r1 +	bsrf	r1 +	 mov	r2, r4 +.Lwait5b: +	bra	13b +	 nop + +	.align	2 +.Lwait4: +	.long	__lll_lock_wait-.Lwait4b +.Lwake4: +	.long	__lll_unlock_wake-.Lwake4b +.Lwait5: +	.long	__lll_lock_wait-.Lwait5b +.Lwake5: +	.long	__lll_unlock_wake-.Lwake5b +	.globl	pthread_rwlock_wrlock +pthread_rwlock_wrlock = __pthread_rwlock_wrlock + +	.globl	__pthread_rwlock_wrlock_internal +__pthread_rwlock_wrlock_internal = __pthread_rwlock_wrlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_post.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_post.S new file mode 100644 index 000000000..f71cd930d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_post.S @@ -0,0 +1,110 @@ +/* Copyright (C) 2003, 2004, 2007, 2008 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <structsem.h> +#include <lowlevellock.h> +#include "lowlevel-atomic.h" + + +	.text + +	.globl	__new_sem_post +	.type	__new_sem_post,@function +	.align	5 +__new_sem_post: +	mov.l	@(VALUE,r4), r2 +0: +	mov.l	.Lmax, r1 +	cmp/eq	r1, r2 +	bt/s	3f +	 mov	r2, r3 +	mov	r3, r5 +	add	#1, r5 +	CMPXCHG (r3, @(VALUE,r4), r5, r2) +	bf	0b +	mov.l	@(NWAITERS,r4), r2 +	tst	r2, r2 +	bt	2f +	mov	#FUTEX_WAKE, r5 +	mov.l	@(PRIVATE,r4), r1 +	or	r1, r5 +	mov	#1, r6 +	mov	#0, r7 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD + +	cmp/pz	r0 +	bf	1f +2: +	rts +	 mov	#0, r0 + +1: +	bra	4f +	 mov	#EINVAL, r2 + +3: +	mov	#EOVERFLOW, r2 +4: +	mov.l	r12, @-r15 +	mov.l	r8, @-r15 +	sts.l	pr, @-r15 +	mova	.Lgot3, r0 +	mov.l	.Lgot3, r12 +	add	r0, r12 + +#if USE___THREAD +	mov.l	.Lerrno3, r0 +	stc	gbr, r1 +	mov.l	@(r0, r12), r0 +	bra	.Lexit +	 add	r1, r0 +	.align	2 +.Lerrno3: +	.long	errno@GOTTPOFF +.Lexit: +	mov.l	r2, @r0 +#else +	mov	r2, r8 +	mov.l	.Lerrloc3, r1 +	bsrf	r1 +	 nop +.Lerrloc3b: +	mov	r8, @r0 +#endif +	lds.l	@r15+, pr +	mov.l	@r15+, r8 +	mov.l	@r15+, r12 +	rts +	 mov	#-1, r0 + +	.align	2 +.Lmax: +	.long	SEM_VALUE_MAX +.Lgot3: +	.long	_GLOBAL_OFFSET_TABLE_ +#if !USE___THREAD +.Lerrloc3: +	.long	__errno_location@PLT-(.Lerrloc3b-.) +#endif +	.size	__new_sem_post,.-__new_sem_post +	weak_alias(__new_sem_post, sem_post) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_timedwait.S new file mode 100644 index 000000000..7fb61b273 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_timedwait.S @@ -0,0 +1,358 @@ +/* Copyright (C) 2003, 2004, 2007 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include <structsem.h> +#include <lowlevellock.h> +#include "lowlevel-atomic.h" + + +#if VALUE != 0 +# error "code needs to be rewritten for VALUE != 0" +#endif + +	.text + +	.globl	sem_timedwait +	.type	sem_timedwait,@function +	.align	5 +sem_timedwait: +.LSTARTCODE: +	mov.l	@r4, r0 +2: +	tst	r0, r0 +	bt	1f +	mov	r0, r3 +	mov	r0, r6 +	add	#-1, r3 +	CMPXCHG (r6, @r4, r3, r2) +	bf/s	2b +	 mov	r2, r0 +	rts +	 mov	#0, r0 + +1: +	/* Check whether the timeout value is valid.  */ +	mov.l	r8, @-r15 +.Lpush_r8: +	mov.l	r9, @-r15 +.Lpush_r9: +	mov.l	r10, @-r15 +.Lpush_r10: +	mov.l	r12, @-r15 +.Lpush_r12: +	sts.l	pr, @-r15 +.Lpush_pr: +	add	#-8, r15 +.Lalloc: +	mov	r4, r8 +	mov	r5, r9 + +	/* Check for invalid nanosecond field.  */ +	mov.l	@(4,r9), r0 +	mov.l	.L1g, r1 +	cmp/hs	r1, r0 +	bt/s	6f +	 mov	#EINVAL, r0 +	INC (@(NWAITERS,r8),r2) + +7: +	/* Compute relative timeout.  */ +	mov	r15, r4 +	mov	#0, r5 +	mov	#__NR_gettimeofday, r3 +	trapa	#0x12 +	SYSCALL_INST_PAD + +	mov.l	@(4,r15), r0 +	mov.w	.L1k, r1 +	dmulu.l	r0, r1		/* Milli seconds to nano seconds.  */ +	mov.l	@r9, r2 +	mov.l	@(4,r9), r3 +	mov.l	@r15, r0 +	sts	macl, r1 +	sub	r0, r2 +	clrt +	subc	r1, r3 +	bf	5f +	mov.l	.L1g, r1 +	add	r1, r3 +	add	#-1, r2 +5: +	cmp/pz	r2 +	bf/s	6f		/* Time is already up.  */ +	 mov	#ETIMEDOUT, r0 + +	/* Store relative timeout.  */ +	mov.l	r2, @r15 +	mov.l	r3, @(4,r15) + +.LcleanupSTART: +	mov.l	.Lenable0, r1 +	bsrf	r1 +	 nop +.Lenable0b: +	mov	r0, r10 + +	mov	r8, r4 +#if FUTEX_WAIT == 0 +	mov.l	@(PRIVATE,r8), r5 +#else +	mov.l	@(PRIVATE,r8), r5 +	mov	#FUTEX_WAIT, r0 +	or	r0, r5 +#endif +	mov	#0, r6 +	mov	r15, r7 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD + +	mov.l	.Ldisable0, r1 +	mov	r10, r4 +	bsrf	r1 +	 mov	r0, r10 +.Ldisable0b: +	mov	r10, r0 +.LcleanupEND: + +	tst	r0, r0 +	bt	9f +	cmp/eq	#-EWOULDBLOCK, r0 +	bf	3f +9: +	mov.l	@r8, r0 +8: +	tst	r0, r0 +	bt	7b + +	mov	r0, r3 +	mov	r0, r4 +	add	#-1, r3 +	CMPXCHG (r4, @r8, r3, r2) +	bf/s	8b +	 mov	r2, r0 + +	DEC (@(NWAITERS,r8), r2) +	mov	#0, r0 + +10: +	add	#8, r15 +	lds.l	@r15+, pr +	mov.l	@r15+, r12 +	mov.l	@r15+, r10 +	mov.l	@r15+, r9 +	mov.l	@r15+, r8 +	rts +	 nop + +3: +	neg	r0, r0 +6: +	mov	r0, r10 +	mova	.Lgot2, r0 +	mov.l	.Lgot2, r12 +	add	r0, r12 + +#if USE___THREAD +	mov.l	.Lerrno2, r0 +	stc	gbr, r1 +	mov.l	@(r0, r12), r0 +	bra	.Lexit +	 add	r1, r0 +	.align	2 +.Lerrno2: + 	.long	errno@GOTTPOFF +.Lexit: +#else +	mov.l	.Lerrloc2, r1 +	bsrf	r1 +	 nop +.Lerrloc2b: +#endif +	mov.l	r10, @r0 +	DEC (@(NWAITERS,r8), r2) +	bra	10b +	 mov	#-1, r0 + +.L1k: +	.word	1000 +	.align	2 +.L1g: +	.long	1000000000 +.Lgot2: +	.long	_GLOBAL_OFFSET_TABLE_ +#if !USE___THREAD +.Lerrloc2: +	.long	__errno_location@PLT-(.Lerrloc2b-.) +#endif +.Lenable0: +	.long	__pthread_enable_asynccancel-.Lenable0b +.Ldisable0: +	.long	__pthread_disable_asynccancel-.Ldisable0b +	.size	sem_timedwait,.-sem_timedwait + +	.type	sem_wait_cleanup,@function +sem_wait_cleanup: + 	DEC (@(NWAITERS,r8), r2) +.LcallUR: +	mov.l	.Lresume, r1 +#ifdef __PIC__ +	add	r12, r1 +#endif +	jsr	@r1 +	 nop +	sleep + +	.align	2 +.Lresume: +#ifdef __PIC__ +	.long	_Unwind_Resume@GOTOFF +#else +	.long	_Unwind_Resume +#endif +.LENDCODE: +	.size	sem_wait_cleanup,.-sem_wait_cleanup + + +	.section .gcc_except_table,"a",@progbits +.LexceptSTART: +	.byte	0xff				! @LPStart format (omit) +	.byte	0xff				! @TType format (omit) +	.byte	0x01				! call-site format +						! DW_EH_PE_uleb128 +	.uleb128 .Lcstend-.Lcstbegin +.Lcstbegin: +	.uleb128 .LcleanupSTART-.LSTARTCODE +	.uleb128 .LcleanupEND-.LcleanupSTART +	.uleb128 sem_wait_cleanup-.LSTARTCODE +	.uleb128  0 +	.uleb128 .LcallUR-.LSTARTCODE +	.uleb128 .LENDCODE-.LcallUR +	.uleb128 0 +	.uleb128  0 +.Lcstend: + + +	.section .eh_frame,"a",@progbits +.LSTARTFRAME: +	.ualong	.LENDCIE-.LSTARTCIE		! Length of the CIE. +.LSTARTCIE: +	.ualong	0				! CIE ID. +	.byte	1				! Version number. +#ifdef SHARED +	.string	"zPLR"				! NUL-terminated augmentation +						! string. +#else +	.string	"zPL"				! NUL-terminated augmentation +						! string. +#endif +	.uleb128 1				! Code alignment factor. +	.sleb128 -4				! Data alignment factor. +	.byte	0x11				! Return address register +						! column. +#ifdef SHARED +	.uleb128 7				! Augmentation value length. +	.byte	0x9b				! Personality: DW_EH_PE_pcrel +						! + DW_EH_PE_sdata4 +						! + DW_EH_PE_indirect +	.ualong	DW.ref.__gcc_personality_v0-. +	.byte	0x1b				! LSDA Encoding: DW_EH_PE_pcrel +						! + DW_EH_PE_sdata4. +	.byte	0x1b				! FDE Encoding: DW_EH_PE_pcrel +						! + DW_EH_PE_sdata4. +#else +	.uleb128 6				! Augmentation value length. +	.byte	0x0				! Personality: absolute +	.ualong	__gcc_personality_v0 +	.byte	0x0				! LSDA Encoding: absolute +#endif +	.byte 0x0c				! DW_CFA_def_cfa +	.uleb128 0xf +	.uleb128 0 +	.align 4 +.LENDCIE: + +	.ualong	.LENDFDE-.LSTARTFDE		! Length of the FDE. +.LSTARTFDE: +	.ualong	.LSTARTFDE-.LSTARTFRAME		! CIE pointer. +#ifdef SHARED +	.ualong	.LSTARTCODE-.			! PC-relative start address +						! of the code. +#else +	.ualong	.LSTARTCODE			! Start address of the code. +#endif +	.ualong	.LENDCODE-.LSTARTCODE		! Length of the code. +	.uleb128 4				! Augmentation size +#ifdef SHARED +	.ualong	.LexceptSTART-. +#else +	.ualong	.LexceptSTART +#endif + +	.byte	4				! DW_CFA_advance_loc4 +	.ualong	.Lpush_r8-.LSTARTCODE +	.byte	14				! DW_CFA_def_cfa_offset +	.uleb128 4 +	.byte   0x88				! DW_CFA_offset r8 +        .uleb128 1 +	.byte	4				! DW_CFA_advance_loc4 +	.ualong	.Lpush_r9-.Lpush_r8 +	.byte	14				! DW_CFA_def_cfa_offset +	.uleb128 8 +	.byte   0x89				! DW_CFA_offset r9 +        .uleb128 2 +	.byte	4				! DW_CFA_advance_loc4 +	.ualong	.Lpush_r10-.Lpush_r9 +	.byte	14				! DW_CFA_def_cfa_offset +	.uleb128 12 +	.byte   0x8a				! DW_CFA_offset r10 +        .uleb128 3 +	.byte	4				! DW_CFA_advance_loc4 +	.ualong	.Lpush_r12-.Lpush_r10 +	.byte	14				! DW_CFA_def_cfa_offset +	.uleb128 16 +	.byte   0x8c				! DW_CFA_offset r12 +        .uleb128 4 +	.byte	4				! DW_CFA_advance_loc4 +	.ualong	.Lpush_pr-.Lpush_r12 +	.byte	14				! DW_CFA_def_cfa_offset +	.uleb128 20 +	.byte	0x91				! DW_CFA_offset pr +	.uleb128 5 +	.byte	4				! DW_CFA_advance_loc4 +	.ualong	.Lalloc-.Lpush_pr +	.byte	14				! DW_CFA_def_cfa_offset +	.uleb128 28 +	.align	4 +.LENDFDE: + + +#ifdef SHARED +	.hidden	DW.ref.__gcc_personality_v0 +	.weak	DW.ref.__gcc_personality_v0 +	.section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits +	.align	4 +	.type	DW.ref.__gcc_personality_v0, @object +	.size	DW.ref.__gcc_personality_v0, 4 +DW.ref.__gcc_personality_v0: +	.long	__gcc_personality_v0 +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_trywait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_trywait.S new file mode 100644 index 000000000..b46eb1a56 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_trywait.S @@ -0,0 +1,90 @@ +/* Copyright (C) 2003, 2004, 2007 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <lowlevellock.h> +#include "lowlevel-atomic.h" + + +	.text + +	.globl	__new_sem_trywait +	.type	__new_sem_trywait,@function +	.align	5 +__new_sem_trywait: +	mov.l	r12, @-r15 +	mov.l	r8, @-r15 +	sts.l	pr, @-r15 +	mov	r4, r8 +	mov.l	@r8, r0 +2: +	tst	r0, r0 +	bt	1f + +	mov	r0, r3 +	mov	r0, r4 +	add	#-1, r3 +	CMPXCHG (r4, @r8, r3, r2) +	bf/s	2b +	 mov	r2, r0 + +	lds.l	@r15+, pr +	mov.l	@r15+, r8 +	mov.l	@r15+, r12 +	rts +	 mov	#0, r0 + +1: +	mov	#EAGAIN, r8 +	mova	.Lgot1, r0 +	mov.l	.Lgot1, r12 +	add	r0, r12 + +#if USE___THREAD +	mov.l	.Lerrno1, r0 +	stc	gbr, r1 +	mov.l	@(r0, r12), r0 +	bra	.Lexit +	 add	r1, r0 +	.align	2 +.Lerrno1: +	.long	errno@GOTTPOFF +.Lexit: +#else +	mov.l	.Lerrloc1, r1 +	bsrf	r1 +	 nop +.Lerrloc1b: +#endif +	mov.l	r8, @r0 +	lds.l	@r15+, pr +	mov.l	@r15+, r8 +	mov.l	@r15+, r12 +	rts +	 mov	#-1, r0 + +	.align	2 +.Lgot1: +	.long	_GLOBAL_OFFSET_TABLE_ +#if !USE___THREAD +.Lerrloc1: +	.long	__errno_location@PLT-(.Lerrloc1b-.) +#endif +	.size	__new_sem_trywait,.-__new_sem_trywait +	weak_alias(__new_sem_trywait, sem_trywait) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_wait.S new file mode 100644 index 000000000..00a125bc5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_wait.S @@ -0,0 +1,303 @@ +/* Copyright (C) 2003, 2004, 2007 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include <structsem.h> +#include <lowlevellock.h> +#include "lowlevel-atomic.h" + + +#if VALUE != 0 +# error "code needs to be rewritten for VALUE != 0" +#endif + +	.text + +	.globl	__new_sem_wait +	.type	__new_sem_wait,@function +	.align	5 +__new_sem_wait: +.LSTARTCODE: +	mov.l	r8, @-r15 +.Lpush_r8: +	mov.l	r10, @-r15 +.Lpush_r10: +	mov.l	r12, @-r15 +.Lpush_r12: +	sts.l	pr, @-r15 +.Lpush_pr: +	mov	r4, r8 + +	mov.l	@r8, r0 +2: +	tst	r0, r0 +	bt	1f +	mov	r0, r3 +	mov	r0, r4 +	add	#-1, r3 +	CMPXCHG (r4, @r8, r3, r2) +	bf/s	2b +	 mov	r2, r0 +7: +	mov	#0, r0 +9: +	lds.l	@r15+, pr +	mov.l	@r15+, r12 +	mov.l	@r15+, r10 +	rts +	 mov.l	@r15+, r8 + +.Lafter_ret: +1: +	INC (@(NWAITERS,r8),r2) + +.LcleanupSTART: +6: +	mov.l	.Lenable0, r1 +	bsrf	r1 +	 nop +.Lenable0b: +	mov	r0, r10 + +	mov	r8, r4 +#if FUTEX_WAIT == 0 +	mov.l	@(PRIVATE,r8), r5 +#else +	mov.l	@(PRIVATE,r8), r5 +	mov	#FUTEX_WAIT, r0 +	or	r0, r5 +#endif +	mov	#0, r6 +	mov	#0, r7 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD + +	mov.l	.Ldisable0, r1 +	mov	r10, r4 +	bsrf	r1 +	 mov	r0, r10 +.Ldisable0b: +	mov	r10, r0 +.LcleanupEND: + +	tst	r0, r0 +	bt	3f +	cmp/eq	#-EWOULDBLOCK, r0 +	bf	4f + +3: +	mov.l	@r8, r0 +5: +	tst	r0, r0 +	bt	6b + +	mov	r0, r3 +	mov	r0, r4 +	add	#-1, r3 +	CMPXCHG (r4, @r8, r3, r2) +	bf/s	5b +	 mov	r2, r0 + +	DEC (@(NWAITERS,r8), r2) +	bra	7b +	 nop + +4: +	neg	r0, r0 +	mov	r0, r4 +	DEC (@(NWAITERS,r8), r2) +	mov	r4, r8 +	mova	.Lgot0, r0 +	mov.l	.Lgot0, r12 +	add	r0, r12 + +#if USE___THREAD +	mov.l	.Lerrno0, r0 +	stc	gbr, r1 +	mov.l	@(r0, r12), r0 +	bra	.Lexit +	 add	r1, r0 +	.align	2 +.Lerrno0: +	.long	errno@GOTTPOFF +.Lexit: +#else +	mov.l	.Lerrloc0, r1 +	bsrf	r1 +	 nop +.Lerrloc0b: +#endif +	mov.l	r8, @r0 +	bra	9b +	 mov	#-1, r0 + +	.align	2 +.Lgot0: +	.long	_GLOBAL_OFFSET_TABLE_ +#if !USE___THREAD +.Lerrloc0: +	.long	__errno_location@PLT-(.Lerrloc0b-.) +#endif +.Lenable0: +	.long	__pthread_enable_asynccancel-.Lenable0b +.Ldisable0: +	.long	__pthread_disable_asynccancel-.Ldisable0b +	.size	__new_sem_wait,.-__new_sem_wait +	weak_alias(__new_sem_wait, sem_wait) + + +	.type	sem_wait_cleanup,@function +sem_wait_cleanup: + 	DEC (@(NWAITERS,r8), r2) +.LcallUR: +	mov.l	.Lresume, r1 +#ifdef __PIC__ +	add	r12, r1 +#endif +	jsr	@r1 +	 nop +	sleep + +	.align	2 +.Lresume: +#ifdef __PIC__ +	.long	_Unwind_Resume@GOTOFF +#else +	.long	_Unwind_Resume +#endif +.LENDCODE: +	.size	sem_wait_cleanup,.-sem_wait_cleanup + + +	.section .gcc_except_table,"a",@progbits +.LexceptSTART: +	.byte	0xff				! @LPStart format (omit) +	.byte	0xff				! @TType format (omit) +	.byte	0x01				! call-site format +						! DW_EH_PE_uleb128 +	.uleb128 .Lcstend-.Lcstbegin +.Lcstbegin: +	.uleb128 .LcleanupSTART-.LSTARTCODE +	.uleb128 .LcleanupEND-.LcleanupSTART +	.uleb128 sem_wait_cleanup-.LSTARTCODE +	.uleb128  0 +	.uleb128 .LcallUR-.LSTARTCODE +	.uleb128 .LENDCODE-.LcallUR +	.uleb128 0 +	.uleb128  0 +.Lcstend: + + +	.section .eh_frame,"a",@progbits +.LSTARTFRAME: +	.ualong	.LENDCIE-.LSTARTCIE		! Length of the CIE. +.LSTARTCIE: +	.ualong	0				! CIE ID. +	.byte	1				! Version number. +#ifdef SHARED +	.string	"zPLR"				! NUL-terminated augmentation +						! string. +#else +	.string	"zPL"				! NUL-terminated augmentation +						! string. +#endif +	.uleb128 1				! Code alignment factor. +	.sleb128 -4				! Data alignment factor. +	.byte	0x11				! Return address register +						! column. +#ifdef SHARED +	.uleb128 7				! Augmentation value length. +	.byte	0x9b				! Personality: DW_EH_PE_pcrel +						! + DW_EH_PE_sdata4 +						! + DW_EH_PE_indirect +	.ualong	DW.ref.__gcc_personality_v0-. +	.byte	0x1b				! LSDA Encoding: DW_EH_PE_pcrel +						! + DW_EH_PE_sdata4. +	.byte	0x1b				! FDE Encoding: DW_EH_PE_pcrel +						! + DW_EH_PE_sdata4. +#else +	.uleb128 6				! Augmentation value length. +	.byte	0x0				! Personality: absolute +	.ualong	__gcc_personality_v0 +	.byte	0x0				! LSDA Encoding: absolute +#endif +	.byte 0x0c				! DW_CFA_def_cfa +	.uleb128 0xf +	.uleb128 0 +	.align 4 +.LENDCIE: + +	.ualong	.LENDFDE-.LSTARTFDE		! Length of the FDE. +.LSTARTFDE: +	.ualong	.LSTARTFDE-.LSTARTFRAME		! CIE pointer. +#ifdef SHARED +	.ualong	.LSTARTCODE-.			! PC-relative start address +						! of the code. +#else +	.ualong	.LSTARTCODE			! Start address of the code. +#endif +	.ualong	.LENDCODE-.LSTARTCODE		! Length of the code. +	.uleb128 4				! Augmentation size +#ifdef SHARED +	.ualong	.LexceptSTART-. +#else +	.ualong	.LexceptSTART +#endif + +	.byte	4				! DW_CFA_advance_loc4 +	.ualong	.Lpush_r8-.LSTARTCODE +	.byte	14				! DW_CFA_def_cfa_offset +	.uleb128 4 +	.byte   0x88				! DW_CFA_offset r8 +        .uleb128 1 +	.byte	4				! DW_CFA_advance_loc4 +	.ualong	.Lpush_r10-.Lpush_r8 +	.byte	14				! DW_CFA_def_cfa_offset +	.uleb128 8 +	.byte   0x8a				! DW_CFA_offset r10 +        .uleb128 2 +	.byte	4				! DW_CFA_advance_loc4 +	.ualong	.Lpush_r12-.Lpush_r10 +	.byte	14				! DW_CFA_def_cfa_offset +	.uleb128 12 +	.byte   0x8c				! DW_CFA_offset r12 +        .uleb128 3 +	.byte	4				! DW_CFA_advance_loc4 +	.ualong	.Lpush_pr-.Lpush_r12 +	.byte	14				! DW_CFA_def_cfa_offset +	.uleb128 16 +	.byte   0x91				! DW_CFA_offset pr +        .uleb128 4 +	.align	4 +.LENDFDE: + + +#ifdef SHARED +	.hidden	DW.ref.__gcc_personality_v0 +	.weak	DW.ref.__gcc_personality_v0 +	.section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits +	.align	4 +	.type	DW.ref.__gcc_personality_v0, @object +	.size	DW.ref.__gcc_personality_v0, 4 +DW.ref.__gcc_personality_v0: +	.long	__gcc_personality_v0 +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sh4/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sh4/lowlevellock.h new file mode 100644 index 000000000..8cdcac556 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sh4/lowlevellock.h @@ -0,0 +1,4 @@ +/*  4 instruction cycles not accessing cache and TLB are needed after +    trapa instruction to avoid an SH-4 silicon bug.  */ +#define NEED_SYSCALL_INST_PAD +#include <sysdeps/unix/sysv/linux/sh/lowlevellock.h> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/smp.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/smp.h new file mode 100644 index 000000000..2c0cbe99a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/smp.h @@ -0,0 +1,24 @@ +/* Determine whether the host has multiple processors.  SH version. +   Copyright (C) 2002 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 Library General Public License as +   published by the Free Software Foundation; either version 2 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 +   Library General Public License for more details. + +   You should have received a copy of the GNU Library General Public +   License along with the GNU C Library; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +static inline int +is_smp_system (void) +{ +  return 0; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sysdep-cancel.h new file mode 100644 index 000000000..ad2ca40ac --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sysdep-cancel.h @@ -0,0 +1,169 @@ +/* Copyright (C) 2003, 2004, 2005, 2006 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <tls.h> +#include <sysdep.h> +#ifndef __ASSEMBLER__ +# include <pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# define _IMM12 #-12 +# define _IMM16 #-16 +# define _IMP16 #16 +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ +  .text; \ +  ENTRY (name); \ +  .Lpseudo_start: \ +    SINGLE_THREAD_P; \ +    bf .Lpseudo_cancel; \ +    .type __##syscall_name##_nocancel,@function; \ +    .globl __##syscall_name##_nocancel; \ +    __##syscall_name##_nocancel: \ +    DO_CALL (syscall_name, args); \ +    mov r0,r1; \ +    mov _IMM12,r2; \ +    shad r2,r1; \ +    not r1,r1; \ +    tst r1,r1; \ +    bt .Lsyscall_error; \ +    bra .Lpseudo_end; \ +     nop; \ +    .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \ + .Lpseudo_cancel: \ +    sts.l pr,@-r15; \ +    cfi_adjust_cfa_offset (4); \ +    cfi_rel_offset (pr, 0); \ +    add _IMM16,r15; \ +    cfi_adjust_cfa_offset (16); \ +    SAVE_ARGS_##args; \ +    CENABLE; \ +    LOAD_ARGS_##args; \ +    add _IMP16,r15; \ +    cfi_adjust_cfa_offset (-16); \ +    lds.l @r15+,pr; \ +    cfi_adjust_cfa_offset (-4); \ +    cfi_restore (pr); \ +    DO_CALL(syscall_name, args); \ +    SYSCALL_INST_PAD; \ +    sts.l pr,@-r15; \ +    cfi_adjust_cfa_offset (4); \ +    cfi_rel_offset (pr, 0); \ +    mov.l r0,@-r15; \ +    cfi_adjust_cfa_offset (4); \ +    cfi_rel_offset (r0, 0); \ +    CDISABLE; \ +    mov.l @r15+,r0; \ +    cfi_adjust_cfa_offset (-4); \ +    lds.l @r15+,pr; \ +    cfi_adjust_cfa_offset (-4); \ +    cfi_restore (pr); \ +    mov r0,r1; \ +    mov _IMM12,r2; \ +    shad r2,r1; \ +    not r1,r1; \ +    tst r1,r1; \ +    bf .Lpseudo_end; \ + .Lsyscall_error: \ +    SYSCALL_ERROR_HANDLER; \ + .Lpseudo_end: + +# undef PSEUDO_END +# define PSEUDO_END(sym) \ +  END (sym) + +# define SAVE_ARGS_0	/* Nothing.  */ +# define SAVE_ARGS_1	SAVE_ARGS_0; mov.l r4,@(0,r15); cfi_offset (r4,-4) +# define SAVE_ARGS_2	SAVE_ARGS_1; mov.l r5,@(4,r15); cfi_offset (r5,-8) +# define SAVE_ARGS_3	SAVE_ARGS_2; mov.l r6,@(8,r15); cfi_offset (r6,-12) +# define SAVE_ARGS_4	SAVE_ARGS_3; mov.l r7,@(12,r15); cfi_offset (r7,-16) +# define SAVE_ARGS_5	SAVE_ARGS_4 +# define SAVE_ARGS_6	SAVE_ARGS_5 + +# define LOAD_ARGS_0	/* Nothing.  */ +# define LOAD_ARGS_1	LOAD_ARGS_0; mov.l @(0,r15),r4 +# define LOAD_ARGS_2	LOAD_ARGS_1; mov.l @(4,r15),r5 +# define LOAD_ARGS_3	LOAD_ARGS_2; mov.l @(8,r15),r6 +# define LOAD_ARGS_4	LOAD_ARGS_3; mov.l @(12,r15),r7 +# define LOAD_ARGS_5	LOAD_ARGS_4 +# define LOAD_ARGS_6	LOAD_ARGS_5 + +# ifdef IS_IN_libpthread +#  define __local_enable_asynccancel	__pthread_enable_asynccancel +#  define __local_disable_asynccancel	__pthread_disable_asynccancel +# elif !defined NOT_IN_libc +#  define __local_enable_asynccancel	__libc_enable_asynccancel +#  define __local_disable_asynccancel	__libc_disable_asynccancel +# elif defined IS_IN_librt +#  define __local_enable_asynccancel	__librt_enable_asynccancel +#  define __local_disable_asynccancel	__librt_disable_asynccancel +# else +#  error Unsupported library +# endif + +# define CENABLE \ +	mov.l 1f,r0; \ +	bsrf r0; \ +	 nop; \ +     0: bra 2f; \ +	 mov r0,r2; \ +	.align 2; \ +     1: .long __local_enable_asynccancel - 0b; \ +     2: + +# define CDISABLE \ +	mov.l 1f,r0; \ +	bsrf r0; \ +	 mov r2,r4; \ +     0: bra 2f; \ +	 nop; \ +	.align 2; \ +     1: .long __local_disable_asynccancel - 0b; \ +     2: + +# ifndef __ASSEMBLER__ +#  define SINGLE_THREAD_P \ +  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ +				   header.multiple_threads) == 0, 1) +# else +#  define SINGLE_THREAD_P \ +	stc gbr,r0; \ +	mov.w 0f,r1; \ +	sub r1,r0; \ +	mov.l @(MULTIPLE_THREADS_OFFSET,r0),r0; \ +	bra 1f; \ +	 tst r0,r0; \ +     0: .word TLS_PRE_TCB_SIZE; \ +     1: + +# 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/libpthread/nptl/sysdeps/unix/sysv/linux/sh/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/vfork.S new file mode 100644 index 000000000..a45c09fd6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/vfork.S @@ -0,0 +1,71 @@ +/* Copyright (C) 2004 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#define _ERRNO_H	1 +#include <bits/errno.h> +#include <tcb-offsets.h> + +/* Clone the calling process, but without copying the whole address space. +   The calling process is suspended until the new process exits or is +   replaced by a call to `execve'.  Return -1 for errors, 0 to the new process, +   and the process ID of the new process to the old process.  */ + +ENTRY (__vfork) +	/* Save the PID value.  */ +	stc	gbr, r2 +	mov.w	.L2, r0 +	mov.l	@(r0,r2), r4 +	neg	r4, r1 +	tst	r1, r1 +	bf	1f +	mov	#1, r1 +	rotr	r1 +1: +	mov.l	r1, @(r0,r2) + +	mov.w	.L1, r3 +	trapa	#0x10 +	mov     r0, r1 + +	/* Restore the old PID value in the parent.  */ +	tst	r0, r0 +	bt.s	2f +	 stc	gbr, r2 +	mov.w	.L2, r0 +	mov.l	r4, @(r0,r2) +	mov	r1, r0 +2: +	mov	#-12, r2 +	shad	r2, r1 +	not	r1, r1			// r1=0 means r0 = -1 to -4095 +	tst	r1, r1			// i.e. error in linux +	bf	.Lpseudo_end +	SYSCALL_ERROR_HANDLER +.Lpseudo_end: +	rts +	 nop +.L1: +	.word	__NR_vfork +.L2: +	.word	PID - TLS_PRE_TCB_SIZE +	.align	2 +PSEUDO_END (__vfork) +hidden_def (vfork) + +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sigtimedwait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sigtimedwait.c new file mode 100644 index 000000000..5159bf9b8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sigtimedwait.c @@ -0,0 +1,88 @@ +/* Copyright (C) 1997,1998,2000,2002,2003,2004 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <pthreadP.h> +#include <errno.h> +#include <signal.h> +#include <string.h> + +#include <sysdep-cancel.h> +#include <sys/syscall.h> + +#ifdef __NR_rt_sigtimedwait + +static int +do_sigtimedwait (const sigset_t *set, siginfo_t *info, +		 const struct timespec *timeout) +{ +#ifdef SIGCANCEL +  sigset_t tmpset; +  if (set != NULL +      && (__builtin_expect (__sigismember (set, SIGCANCEL), 0) +# ifdef SIGSETXID +	  || __builtin_expect (__sigismember (set, SIGSETXID), 0) +# endif +	  )) +    { +      /* Create a temporary mask without the bit for SIGCANCEL set.  */ +      // We are not copying more than we have to. +      memcpy (&tmpset, set, _NSIG / 8); +      __sigdelset (&tmpset, SIGCANCEL); +# ifdef SIGSETXID +      __sigdelset (&tmpset, SIGSETXID); +# endif +      set = &tmpset; +    } +#endif + +    /* XXX The size argument hopefully will have to be changed to the +       real size of the user-level sigset_t.  */ +  int result = INLINE_SYSCALL (rt_sigtimedwait, 4, set, +			       info, timeout, _NSIG / 8); + +  /* The kernel generates a SI_TKILL code in si_code in case tkill is +     used.  tkill is transparently used in raise().  Since having +     SI_TKILL as a code is useful in general we fold the results +     here.  */ +  if (result != -1 && info != NULL && info->si_code == SI_TKILL) +    info->si_code = SI_USER; + +  return result; +} + + +/* Return any pending signal or wait for one for the given time.  */ +int attribute_hidden +__sigtimedwait (const sigset_t *set, siginfo_t *info, +		const struct timespec *timeout) +{ +  if (SINGLE_THREAD_P) +    return do_sigtimedwait (set, info, timeout); + +  int oldtype = LIBC_CANCEL_ASYNC (); + +  /* XXX The size argument hopefully will have to be changed to the +     real size of the user-level sigset_t.  */ +  int result = do_sigtimedwait (set, info, timeout); + +  LIBC_CANCEL_RESET (oldtype); + +  return result; +} +weak_alias (__sigtimedwait, sigtimedwait) +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sigwait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sigwait.c new file mode 100644 index 000000000..bde0a9292 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sigwait.c @@ -0,0 +1,2 @@ +#include <pthreadP.h> +#include "../../../../../../libc/signal/sigwait.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sigwaitinfo.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sigwaitinfo.c new file mode 100644 index 000000000..6c47fdee6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sigwaitinfo.c @@ -0,0 +1,88 @@ +/* Copyright (C) 1997,1998,2000,2002,2003,2004 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <pthreadP.h> +#include <errno.h> +#include <signal.h> +#define __need_NULL +#include <stddef.h> +#include <string.h> + +#include <sysdep-cancel.h> +#include <sys/syscall.h> + +#ifdef __NR_rt_sigtimedwait + +static int +do_sigwaitinfo (const sigset_t *set, siginfo_t *info) +{ +#ifdef SIGCANCEL +  sigset_t tmpset; +  if (set != NULL +      && (__builtin_expect (__sigismember (set, SIGCANCEL), 0) +# ifdef SIGSETXID +	  || __builtin_expect (__sigismember (set, SIGSETXID), 0) +# endif +	  )) +    { +      /* Create a temporary mask without the bit for SIGCANCEL set.  */ +      // We are not copying more than we have to. +      memcpy (&tmpset, set, _NSIG / 8); +      __sigdelset (&tmpset, SIGCANCEL); +# ifdef SIGSETXID +      __sigdelset (&tmpset, SIGSETXID); +# endif +      set = &tmpset; +    } +#endif + +  /* XXX The size argument hopefully will have to be changed to the +     real size of the user-level sigset_t.  */ +  int result = INLINE_SYSCALL (rt_sigtimedwait, 4, set, +			       info, NULL, _NSIG / 8); + +  /* The kernel generates a SI_TKILL code in si_code in case tkill is +     used.  tkill is transparently used in raise().  Since having +     SI_TKILL as a code is useful in general we fold the results +     here.  */ +  if (result != -1 && info != NULL && info->si_code == SI_TKILL) +    info->si_code = SI_USER; + +  return result; +} + + +/* Return any pending signal or wait for one for the given time.  */ +int +__sigwaitinfo (const sigset_t *set, siginfo_t *info) +{ +  if (SINGLE_THREAD_P) +    return do_sigwaitinfo (set, info); + +  int oldtype = LIBC_CANCEL_ASYNC (); + +  /* XXX The size argument hopefully will have to be changed to the +     real size of the user-level sigset_t.  */ +  int result = do_sigwaitinfo (set, info); + +  LIBC_CANCEL_RESET (oldtype); + +  return result; +} +weak_alias (__sigwaitinfo, sigwaitinfo) +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sleep.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sleep.c new file mode 100644 index 000000000..9e948adce --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sleep.c @@ -0,0 +1,2 @@ +#include <pthreadP.h> +#include <../../../../../../libc/unistd/sleep.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/smp.h b/libpthread/nptl/sysdeps/unix/sysv/linux/smp.h new file mode 100644 index 000000000..fcc34f768 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/smp.h @@ -0,0 +1,28 @@ +/* Determine whether the host has multiple processors.  Linux version. +   Copyright (C) 1996, 2002, 2004, 2006 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 Library General Public License as +   published by the Free Software Foundation; either version 2 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 +   Library General Public License for more details. + +   You should have received a copy of the GNU Library General Public +   License along with the GNU C Library; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +/* Test whether the machine has more than one processor.  This is not the +   best test but good enough.  More complicated tests would require `malloc' +   which is not available at that time.  */ +static inline int +is_smp_system (void) +{ +  /* Assume all machines are SMP and/or CMT and/or SMT.  */ +  return 1; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile new file mode 100644 index 000000000..43a6fad84 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../../../../ +top_builddir=../../../../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.arch +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile.arch new file mode 100644 index 000000000..1e4f54488 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile.arch @@ -0,0 +1,67 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_SSRC = pt-vfork.S clone.S +libpthread_CSRC = pthread_once.c lowlevellock.c \ +				  pthread_barrier_init.c pthread_barrier_wait.c pthread_barrier_destroy.c + +libc_a_CSRC = fork.c libc-lowlevellock.c +libc_a_SSRC = clone.S vfork.S + +CFLAGS-OMIT-fork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-OMIT-libc-lowlevellock.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y) +CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__ +endif + +ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD + +CFLAGS-pthread_once.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-lowlevellock.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + + +ASFLAGS-clone.S = -D_LIBC_REENTRANT +ASFLAGS-vfork.S = -D_LIBC_REENTRANT + +ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) +#Needed to use the correct SYSCALL_ERROR_HANDLER +ASFLAGS-clone.S += -DUSE___THREAD +ASFLAGS-vfork.S += -DUSE___THREAD +ASFLAGS-pt-vfork.S += -DUSE___THREAD +endif + +CFLAGS += $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/sparc +LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/sparc + +LINUX_ARCH_OBJ:=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libpthread_SSRC)) +LINUX_ARCH_OBJ+=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(LINUX_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(LINUX_ARCH_OBJ) +endif +libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y+=$(LINUX_ARCH_OBJS) + +LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC)) +LIBC_LINUX_ARCH_OBJ+=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libc_a_SSRC)) + +libc-static-y+=$(LIBC_LINUX_ARCH_OBJ) +libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS) + +libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ) + +objclean-y+=nptl_linux_arch_clean + +nptl_linux_arch_clean: +	$(do_rm) $(addprefix $(LINUX_ARCH_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h new file mode 100644 index 000000000..6e356031d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h @@ -0,0 +1,100 @@ +/* Minimum guaranteed maximum values for system limits.  Linux/SPARC version. +   Copyright (C) 1993-1998,2000,2002-2004,2008 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 Library General Public License as +   published by the Free Software Foundation; either version 2 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 +   Library General Public License for more details. + +   You should have received a copy of the GNU Library General Public +   License along with the GNU C Library; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +/* The kernel header pollutes the namespace with the NR_OPEN symbol +   and defines LINK_MAX although filesystems have different maxima.  A +   similar thing is true for OPEN_MAX: the limit can be changed at +   runtime and therefore the macro must not be defined.  Remove this +   after including the header if necessary.  */ +#ifndef NR_OPEN +# define __undef_NR_OPEN +#endif +#ifndef LINK_MAX +# define __undef_LINK_MAX +#endif +#ifndef OPEN_MAX +# define __undef_OPEN_MAX +#endif +#ifndef ARG_MAX +# define __undef_ARG_MAX +#endif + +/* The kernel sources contain a file with all the needed information.  */ +#include <linux/limits.h> + +/* Have to remove NR_OPEN?  */ +#ifdef __undef_NR_OPEN +# undef NR_OPEN +# undef __undef_NR_OPEN +#endif +/* Have to remove LINK_MAX?  */ +#ifdef __undef_LINK_MAX +# undef LINK_MAX +# undef __undef_LINK_MAX +#endif +/* Have to remove OPEN_MAX?  */ +#ifdef __undef_OPEN_MAX +# undef OPEN_MAX +# undef __undef_OPEN_MAX +#endif +/* Have to remove ARG_MAX?  */ +#ifdef __undef_ARG_MAX +# undef ARG_MAX +# undef __undef_ARG_MAX +#endif + +/* The number of data keys per process.  */ +#define _POSIX_THREAD_KEYS_MAX	128 +/* This is the value this implementation supports.  */ +#define PTHREAD_KEYS_MAX	1024 + +/* Controlling the iterations of destructors for thread-specific data.  */ +#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS	4 +/* Number of iterations this implementation does.  */ +#define PTHREAD_DESTRUCTOR_ITERATIONS	_POSIX_THREAD_DESTRUCTOR_ITERATIONS + +/* The number of threads per process.  */ +#define _POSIX_THREAD_THREADS_MAX	64 +/* We have no predefined limit on the number of threads.  */ +#undef PTHREAD_THREADS_MAX + +/* Maximum amount by which a process can descrease its asynchronous I/O +   priority level.  */ +#define AIO_PRIO_DELTA_MAX	20 + +/* Minimum size for a thread.  We are free to choose a reasonable value.  */ +#define PTHREAD_STACK_MIN	24576 + +/* Maximum number of timer expiration overruns.  */ +#define DELAYTIMER_MAX	2147483647 + +/* Maximum tty name length.  */ +#define TTY_NAME_MAX		32 + +/* Maximum login name length.  This is arbitrary.  */ +#define LOGIN_NAME_MAX		256 + +/* Maximum host name length.  */ +#define HOST_NAME_MAX		64 + +/* Maximum message queue priority level.  */ +#define MQ_PRIO_MAX		32768 + +/* Maximum value the semaphore can have.  */ +#define SEM_VALUE_MAX   (2147483647) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h new file mode 100644 index 000000000..faf058486 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h @@ -0,0 +1,221 @@ +/* Machine-specific pthread type layouts.  SPARC version. +   Copyright (C) 2003, 2004, 2005, 2006, 2007 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H	1 + +#include <bits/wordsize.h> + +#if __WORDSIZE == 64 +# define __SIZEOF_PTHREAD_ATTR_T 56 +# define __SIZEOF_PTHREAD_MUTEX_T 40 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 56 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 32 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#else +# define __SIZEOF_PTHREAD_ATTR_T 36 +# define __SIZEOF_PTHREAD_MUTEX_T 24 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 32 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 20 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#endif + + +/* Thread identifiers.  The structure of the attribute type is +   deliberately not exposed.  */ +typedef unsigned long int pthread_t; + + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_ATTR_T]; +  long int __align; +} pthread_attr_t; + + +#if __WORDSIZE == 64 +typedef struct __pthread_internal_list +{ +  struct __pthread_internal_list *__prev; +  struct __pthread_internal_list *__next; +} __pthread_list_t; +#else +typedef struct __pthread_internal_slist +{ +  struct __pthread_internal_slist *__next; +} __pthread_slist_t; +#endif + + +/* Data structures for mutex handling.  The structure of the attribute +   type is deliberately not exposed.  */ +typedef union +{ +  struct __pthread_mutex_s +  { +    int __lock; +    unsigned int __count; +    int __owner; +#if __WORDSIZE == 64 +    unsigned int __nusers; +#endif +    /* KIND must stay at this position in the structure to maintain +       binary compatibility.  */ +    int __kind; +#if __WORDSIZE == 64 +    int __spins; +    __pthread_list_t __list; +# define __PTHREAD_MUTEX_HAVE_PREV	1 +#else +    unsigned int __nusers; +    __extension__ union +    { +      int __spins; +      __pthread_slist_t __list; +    }; +#endif +  } __data; +  char __size[__SIZEOF_PTHREAD_MUTEX_T]; +  long int __align; +} pthread_mutex_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; +  int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling.  The structure of +   the attribute type is deliberately not exposed.  */ +typedef union +{ +  struct +  { +    int __lock; +    unsigned int __futex; +    __extension__ unsigned long long int __total_seq; +    __extension__ unsigned long long int __wakeup_seq; +    __extension__ unsigned long long int __woken_seq; +    void *__mutex; +    unsigned int __nwaiters; +    unsigned int __broadcast_seq; +  } __data; +  char __size[__SIZEOF_PTHREAD_COND_T]; +  __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_CONDATTR_T]; +  int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling.  The +   structure of the attribute type is deliberately not exposed.  */ +typedef union +{ +# if __WORDSIZE == 64 +  struct +  { +    int __lock; +    unsigned int __nr_readers; +    unsigned int __readers_wakeup; +    unsigned int __writer_wakeup; +    unsigned int __nr_readers_queued; +    unsigned int __nr_writers_queued; +    int __writer; +    int __shared; +    unsigned long int __pad1; +    unsigned long int __pad2; +    /* FLAGS must stay at this position in the structure to maintain +       binary compatibility.  */ +    unsigned int __flags; +  } __data; +# else +  struct +  { +    int __lock; +    unsigned int __nr_readers; +    unsigned int __readers_wakeup; +    unsigned int __writer_wakeup; +    unsigned int __nr_readers_queued; +    unsigned int __nr_writers_queued; +    unsigned char __pad1; +    unsigned char __pad2; +    unsigned char __shared; +    /* FLAGS must stay at this position in the structure to maintain +       binary compatibility.  */ +    unsigned char __flags; +    int __writer; +  } __data; +# endif +  char __size[__SIZEOF_PTHREAD_RWLOCK_T]; +  long int __align; +} pthread_rwlock_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; +  long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type.  */ +typedef volatile int pthread_spinlock_t; + + +/* POSIX barriers data type.  The structure of the type is +   deliberately not exposed.  */ +typedef union +{ +  char __size[__SIZEOF_PTHREAD_BARRIER_T]; +  long int __align; +} pthread_barrier_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; +  int __align; +} pthread_barrierattr_t; +#endif + + +#endif	/* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/semaphore.h new file mode 100644 index 000000000..8fd7d344e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/semaphore.h @@ -0,0 +1,41 @@ +/* Machine-specific POSIX semaphore type layouts.  SPARC version. +   Copyright (C) 2003 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + +#include <bits/wordsize.h> + +#if __WORDSIZE == 64 +# define __SIZEOF_SEM_T	32 +#else +# define __SIZEOF_SEM_T	16 +#endif + +/* Value returned if `sem_open' failed.  */ +#define SEM_FAILED      ((sem_t *) 0) + + +typedef union +{ +  char __size[__SIZEOF_SEM_T]; +  long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/clone.S new file mode 100644 index 000000000..dfc5e8261 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/clone.S @@ -0,0 +1,5 @@ +#if defined(__arch64__) +#include "./sparc64/clone.S" +#else +#include "./sparc32/clone.S" +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/fork.c new file mode 100644 index 000000000..1cd79110a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/fork.c @@ -0,0 +1,29 @@ +/* Copyright (C) 2003 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sched.h> +#include <signal.h> +#include <sysdep.h> +#include <tls.h> + +#define ARCH_FORK() \ +  INLINE_CLONE_SYSCALL (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, \ +			0, NULL, NULL, &THREAD_SELF->tid) + +#include "../fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/internaltypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/internaltypes.h new file mode 100644 index 000000000..4f400a3fe --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/internaltypes.h @@ -0,0 +1,34 @@ +#ifndef _INTERNALTYPES_H +#include "../internaltypes.h" + +union sparc_pthread_barrier +{ +  struct pthread_barrier b; +  struct sparc_pthread_barrier_s +    { +      unsigned int curr_event; +      int lock; +      unsigned int left; +      unsigned int init_count; +      unsigned char left_lock; +      unsigned char pshared; +    } s; +}; + +struct sparc_new_sem +{ +  unsigned int value; +  unsigned char lock; +  unsigned char private; +  unsigned char pad[2]; +  unsigned long int nwaiters; +}; + +struct sparc_old_sem +{ +  unsigned int value; +  unsigned char lock; +  unsigned char private; +}; + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/libc-lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/libc-lowlevellock.c new file mode 100644 index 000000000..b19282281 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/libc-lowlevellock.c @@ -0,0 +1,21 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +/* No difference to lowlevellock.c, except we lose a couple of functions.  */ +#include "lowlevellock.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.c new file mode 100644 index 000000000..0471d1f79 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.c @@ -0,0 +1,133 @@ +/* low level locking for pthread library.  SPARC version. +   Copyright (C) 2003, 2006, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <sys/time.h> +#include <tls.h> + + +void +__lll_lock_wait_private (int *futex) +{ +  do +    { +      int oldval = atomic_compare_and_exchange_val_24_acq (futex, 2, 1); +      if (oldval != 0) +	lll_futex_wait (futex, 2, LLL_PRIVATE); +    } +  while (atomic_compare_and_exchange_val_24_acq (futex, 2, 0) != 0); +} + + +/* These functions don't get included in libc.so  */ +#ifdef IS_IN_libpthread +void +__lll_lock_wait (int *futex, int private) +{ +  do +    { +      int oldval = atomic_compare_and_exchange_val_24_acq (futex, 2, 1); +      if (oldval != 0) +	lll_futex_wait (futex, 2, private); +    } +  while (atomic_compare_and_exchange_val_24_acq (futex, 2, 0) != 0); +} + + +int +__lll_timedlock_wait (int *futex, const struct timespec *abstime, int private) +{ +  /* Reject invalid timeouts.  */ +  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) +    return EINVAL; + +  do +    { +      struct timeval tv; +      struct timespec rt; + +      /* Get the current time.  */ +      (void) gettimeofday (&tv, NULL); + +      /* Compute relative timeout.  */ +      rt.tv_sec = abstime->tv_sec - tv.tv_sec; +      rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; +      if (rt.tv_nsec < 0) +	{ +	  rt.tv_nsec += 1000000000; +	  --rt.tv_sec; +	} + +      /* Already timed out?  */ +      if (rt.tv_sec < 0) +	return ETIMEDOUT; + +      /* Wait.  */ +      int oldval = atomic_compare_and_exchange_val_24_acq (futex, 2, 1); +      if (oldval != 0) +	lll_futex_timed_wait (futex, 2, &rt, private); +    } +  while (atomic_compare_and_exchange_val_24_acq (futex, 2, 0) != 0); + +  return 0; +} + + +int +__lll_timedwait_tid (int *tidp, const struct timespec *abstime) +{ +  int tid; + +  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) +    return EINVAL; + +  /* Repeat until thread terminated.  */ +  while ((tid = *tidp) != 0) +    { +      struct timeval tv; +      struct timespec rt; + +      /* Get the current time.  */ +      (void) gettimeofday (&tv, NULL); + +      /* Compute relative timeout.  */ +      rt.tv_sec = abstime->tv_sec - tv.tv_sec; +      rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; +      if (rt.tv_nsec < 0) +	{ +	  rt.tv_nsec += 1000000000; +	  --rt.tv_sec; +	} + +      /* Already timed out?  */ +      if (rt.tv_sec < 0) +	return ETIMEDOUT; + +      /* Wait until thread terminates.  The kernel so far does not use +	 the private futex operations for this.  */ +      if (lll_futex_timed_wait (tidp, tid, &rt, LLL_SHARED) == -ETIMEDOUT) +	return ETIMEDOUT; +    } + +  return 0; +} +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.h new file mode 100644 index 000000000..d8fe9be35 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.h @@ -0,0 +1,297 @@ +/* Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009 +   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 Libr	\ary; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H	1 + +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> +#include <atomic.h> +#include <sysdep.h> +#include <bits/kernel-features.h> + + +#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_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(futexp, val, private) \ +  lll_futex_timed_wait (futexp, val, NULL, private) + +#define lll_futex_timed_wait(futexp, val, timespec, private) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +									      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),		      \ +			      __lll_private_flag (FUTEX_WAIT, private),	      \ +			      (val), (timespec));			      \ +    __ret;								      \ +  }) + +#define lll_futex_wake(futexp, nr, private) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +									      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),		      \ +			      __lll_private_flag (FUTEX_WAKE, private),	      \ +			      (nr), 0);					      \ +    __ret;								      \ +  }) + +/* 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);				      \ +  }) + +#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.  */ +#ifdef __sparc32_atomic_do_lock +/* Avoid FUTEX_WAKE_OP if supporting pre-v9 CPUs.  */ +# define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) 1 +#else +# 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);				      \ +  }) +#endif + +static inline int +__attribute__ ((always_inline)) +__lll_trylock (int *futex) +{ +  return atomic_compare_and_exchange_val_24_acq (futex, 1, 0) != 0; +} +#define lll_trylock(futex) __lll_trylock (&(futex)) + +static inline int +__attribute__ ((always_inline)) +__lll_cond_trylock (int *futex) +{ +  return atomic_compare_and_exchange_val_24_acq (futex, 2, 0) != 0; +} +#define lll_cond_trylock(futex) __lll_cond_trylock (&(futex)) + +static inline int +__attribute__ ((always_inline)) +__lll_robust_trylock (int *futex, int id) +{ +  return atomic_compare_and_exchange_val_acq (futex, id, 0) != 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) +{ +  int val = atomic_compare_and_exchange_val_24_acq (futex, 1, 0); + +  if (__builtin_expect (val != 0, 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 (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) +{ +  int val = atomic_compare_and_exchange_val_24_acq (futex, 2, 0); + +  if (__builtin_expect (val != 0, 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 val = atomic_compare_and_exchange_val_24_acq (futex, 1, 0); +  int result = 0; + +  if (__builtin_expect (val != 0, 0)) +    result = __lll_timedlock_wait (futex, abstime, private); +  return result; +} +#define lll_timedlock(futex, abstime, private) \ +  __lll_timedlock (&(futex), abstime, private) + +static inline int +__attribute__ ((always_inline)) +__lll_robust_timedlock (int *futex, const struct timespec *abstime, +			int id, int private) +{ +  int result = 0; +  if (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(lock, private) \ +  ((void) ({								      \ +    int *__futex = &(lock);						      \ +    int __val = atomic_exchange_24_rel (__futex, 0);			      \ +    if (__builtin_expect (__val > 1, 0))				      \ +      lll_futex_wake (__futex, 1, private);				      \ +  })) + +#define lll_robust_unlock(lock, private) \ +  ((void) ({								      \ +    int *__futex = &(lock);						      \ +    int __val = atomic_exchange_rel (__futex, 0);			      \ +    if (__builtin_expect (__val & FUTEX_WAITERS, 0))			      \ +      lll_futex_wake (__futex, 1, 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 with uses CLONE_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(tid) \ +  do							\ +    {							\ +      __typeof (tid) __tid;				\ +      while ((__tid = (tid)) != 0)			\ +	lll_futex_wait (&(tid), __tid, LLL_SHARED);	\ +    }							\ +  while (0) + +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;						\ +  }) + +#endif	/* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pt-vfork.S new file mode 100644 index 000000000..e8705c54b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pt-vfork.S @@ -0,0 +1,5 @@ +#if defined(__arch64__) +#include "sparc64/pt-vfork.S" +#else +#include "sparc32/pt-vfork.S" +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_barrier_destroy.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_barrier_destroy.c new file mode 100644 index 000000000..ca96379c9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_barrier_destroy.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2002, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include "pthreadP.h" +#include <lowlevellock.h> + +int +pthread_barrier_destroy ( +     pthread_barrier_t *barrier) +{ +  union sparc_pthread_barrier *ibarrier; +  int result = EBUSY; + +  ibarrier = (union sparc_pthread_barrier *) barrier; + +  int private = ibarrier->s.pshared ? LLL_SHARED : LLL_PRIVATE; + +  lll_lock (ibarrier->b.lock, private); + +  if (__builtin_expect (ibarrier->b.left == ibarrier->b.init_count, 1)) +    /* The barrier is not used anymore.  */ +    result = 0; +  else +    /* Still used, return with an error.  */ +    lll_unlock (ibarrier->b.lock, private); + +  return result; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_barrier_init.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_barrier_init.c new file mode 100644 index 000000000..8182f1cef --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_barrier_init.c @@ -0,0 +1,55 @@ +/* Copyright (C) 2002, 2006, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include "pthreadP.h" +#include <lowlevellock.h> + +int +pthread_barrier_init ( +     pthread_barrier_t *barrier, +     const pthread_barrierattr_t *attr, +     unsigned int count) +{ +  union sparc_pthread_barrier *ibarrier; + +  if (__builtin_expect (count == 0, 0)) +    return EINVAL; + +  struct pthread_barrierattr *iattr = (struct pthread_barrierattr *) attr; +  if (iattr != NULL) +    { +      if (iattr->pshared != PTHREAD_PROCESS_PRIVATE +	  && __builtin_expect (iattr->pshared != PTHREAD_PROCESS_SHARED, 0)) +	/* Invalid attribute.  */ +	return EINVAL; +    } + +  ibarrier = (union sparc_pthread_barrier *) barrier; + +  /* Initialize the individual fields.  */ +  ibarrier->b.lock = LLL_LOCK_INITIALIZER; +  ibarrier->b.left = count; +  ibarrier->b.init_count = count; +  ibarrier->b.curr_event = 0; +  ibarrier->s.left_lock = 0; +  ibarrier->s.pshared = (iattr && iattr->pshared == PTHREAD_PROCESS_SHARED); + +  return 0; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_barrier_wait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_barrier_wait.c new file mode 100644 index 000000000..73eaa695e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_barrier_wait.c @@ -0,0 +1 @@ +#include "sparc32/pthread_barrier_wait.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_once.c new file mode 100644 index 000000000..24b74aca6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_once.c @@ -0,0 +1,95 @@ +/* Copyright (C) 2003, 2004, 2007 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#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 +attribute_protected +__pthread_once (once_control, init_routine) +     pthread_once_t *once_control; +     void (*init_routine) (void); +{ +  while (1) +    { +      int oldval, val, newval; + +      val = *once_control; +      do +	{ +	  /* Check if the initialized has already been done.  */ +	  if ((val & 2) != 0) +	    return 0; + +	  oldval = val; +	  newval = (oldval & 3) | __fork_generation | 1; +	  val = atomic_compare_and_exchange_val_acq (once_control, newval, +						     oldval); +	} +      while (__builtin_expect (val != oldval, 0)); + +      /* 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.  */ +      atomic_increment (once_control); + +      /* Wake up all other threads.  */ +      lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE); +      break; +    } + +  return 0; +} +weak_alias (__pthread_once, pthread_once) +strong_alias (__pthread_once, __pthread_once_internal) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sem_init.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sem_init.c new file mode 100644 index 000000000..f694b5e93 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sem_init.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2002, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include <string.h> +#include <semaphore.h> +#include <lowlevellock.h> +#include "semaphoreP.h" +#include <bits/kernel-features.h> + + +int +__new_sem_init (sem, pshared, value) +     sem_t *sem; +     int pshared; +     unsigned int value; +{ +  /* Parameter sanity check.  */ +  if (__builtin_expect (value > SEM_VALUE_MAX, 0)) +    { +      __set_errno (EINVAL); +      return -1; +    } + +  /* Map to the internal type.  */ +  struct sparc_new_sem *isem = (struct sparc_new_sem *) sem; + +  /* Use the values the user provided.  */ +  memset (isem, '\0', sizeof (*isem)); +  isem->value = value; +#ifdef __ASSUME_PRIVATE_FUTEX +  isem->private = pshared ? 0 : FUTEX_PRIVATE_FLAG; +#else +  isem->private = pshared ? 0 : THREAD_GETMEM (THREAD_SELF, +					       header.private_futex); +#endif + +  return 0; +} +weak_alias(__new_sem_init, sem_init) + diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S new file mode 100644 index 000000000..a6142aafe --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S @@ -0,0 +1,2 @@ +#define RESET_PID +#include <libc/sysdeps/linux/sparc/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pt-vfork.S new file mode 100644 index 000000000..fb01242b5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pt-vfork.S @@ -0,0 +1,45 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + +   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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <tcb-offsets.h> + +	.text +	.globl		__syscall_error +ENTRY(__vfork) +	ld	[%g7 + PID], %o5 +	sub	%g0, %o5, %o4 +	st	%o4, [%g7 + PID] + +	LOADSYSCALL(vfork) +	ta	0x10 +	bcc	2f +	 mov	%o7, %g1 +	st	%o5, [%g7 + PID] +	call	__syscall_error +	 mov	%g1, %o7 +2:	sub	%o1, 1, %o1 +	andcc	%o0, %o1, %o0 +	bne,a	1f +	 st	%o5, [%g7 + PID] +1:	retl +	 nop +END(__vfork) + +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pthread_barrier_wait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pthread_barrier_wait.c new file mode 100644 index 000000000..302d1b371 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pthread_barrier_wait.c @@ -0,0 +1,94 @@ +/* Copyright (C) 2003, 2004, 2006, 2007 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthreadP.h> + +/* Wait on barrier.  */ +int +pthread_barrier_wait ( +     pthread_barrier_t *barrier) +{ +  union sparc_pthread_barrier *ibarrier +    = (union sparc_pthread_barrier *) barrier; +  int result = 0; +  int private = ibarrier->s.pshared ? LLL_SHARED : LLL_PRIVATE; + +  /* Make sure we are alone.  */ +  lll_lock (ibarrier->b.lock, private); + +  /* One more arrival.  */ +  --ibarrier->b.left; + +  /* Are these all?  */ +  if (ibarrier->b.left == 0) +    { +      /* Yes. Increment the event counter to avoid invalid wake-ups and +	 tell the current waiters that it is their turn.  */ +      ++ibarrier->b.curr_event; + +      /* Wake up everybody.  */ +      lll_futex_wake (&ibarrier->b.curr_event, INT_MAX, private); + +      /* This is the thread which finished the serialization.  */ +      result = PTHREAD_BARRIER_SERIAL_THREAD; +    } +  else +    { +      /* The number of the event we are waiting for.  The barrier's event +	 number must be bumped before we continue.  */ +      unsigned int event = ibarrier->b.curr_event; + +      /* Before suspending, make the barrier available to others.  */ +      lll_unlock (ibarrier->b.lock, private); + +      /* Wait for the event counter of the barrier to change.  */ +      do +	lll_futex_wait (&ibarrier->b.curr_event, event, private); +      while (event == ibarrier->b.curr_event); +    } + +  /* Make sure the init_count is stored locally or in a register.  */ +  unsigned int init_count = ibarrier->b.init_count; + +  /* If this was the last woken thread, unlock.  */ +  if (__atomic_is_v9 || ibarrier->s.pshared == 0) +    { +      if (atomic_increment_val (&ibarrier->b.left) == init_count) +	/* We are done.  */ +	lll_unlock (ibarrier->b.lock, private); +    } +  else +    { +      unsigned int left; +      /* Slightly more complicated.  On pre-v9 CPUs, atomic_increment_val +	 is only atomic for threads within the same process, not for +	 multiple processes.  */ +      __sparc32_atomic_do_lock24 (&ibarrier->s.left_lock); +      left = ++ibarrier->b.left; +      __sparc32_atomic_do_unlock24 (&ibarrier->s.left_lock); +      if (left == init_count) +        /* We are done.  */ +	lll_unlock (ibarrier->b.lock, private); +    } + +  return result; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_post.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_post.c new file mode 100644 index 000000000..940728eeb --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_post.c @@ -0,0 +1,55 @@ +/* sem_post -- post to a POSIX semaphore.  SPARC version. +   Copyright (C) 2003, 2004, 2006, 2007 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <internaltypes.h> +#include <semaphore.h> + +int +__new_sem_post (sem_t *sem) +{ +  struct sparc_new_sem *isem = (struct sparc_new_sem *) sem; +  int nr; + +  if (__atomic_is_v9) +    nr = atomic_increment_val (&isem->value); +  else +    { +      __sparc32_atomic_do_lock24 (&isem->lock); +      nr = ++(isem->value); +      __sparc32_atomic_do_unlock24 (&isem->lock); +    } +  atomic_full_barrier (); +  if (isem->nwaiters > 0) +    { +      int err = lll_futex_wake (&isem->value, 1, +				isem->private ^ FUTEX_PRIVATE_FLAG); +      if (__builtin_expect (err, 0) < 0) +	{ +	  __set_errno (-err); +	  return -1; +	} +    } +  return 0; +} +weak_alias(__new_sem_post, sem_post) + diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_timedwait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_timedwait.c new file mode 100644 index 000000000..aa5bd80ed --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_timedwait.c @@ -0,0 +1,148 @@ +/* sem_timedwait -- wait on a semaphore.  SPARC version. +   Copyright (C) 2003, 2006, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <internaltypes.h> +#include <semaphore.h> + +#include <pthreadP.h> + + +extern void __sem_wait_cleanup (void *arg) attribute_hidden; + + +int +sem_timedwait (sem_t *sem, const struct timespec *abstime) +{ +  struct sparc_new_sem *isem = (struct sparc_new_sem *) sem; +  int err; +  int val; + +  if (__atomic_is_v9) +    val = atomic_decrement_if_positive (&isem->value); +  else +    { +      __sparc32_atomic_do_lock24 (&isem->lock); +      val = isem->value; +      if (val > 0) +        isem->value = val - 1; +      __sparc32_atomic_do_unlock24 (&isem->lock); +    } + +  if (val > 0) +    return 0; + +  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) +    { +      __set_errno (EINVAL); +      return -1; +    } + +  if (__atomic_is_v9) +    atomic_increment (&isem->nwaiters); +  else +    { +      __sparc32_atomic_do_lock24 (&isem->lock); +      isem->nwaiters++; +      __sparc32_atomic_do_unlock24 (&isem->lock); +    } + +  pthread_cleanup_push (__sem_wait_cleanup, isem); + +  while (1) +    { +      struct timeval tv; +      struct timespec rt; +      int sec, nsec; + +      /* Get the current time.  */ +      __gettimeofday (&tv, NULL); + +      /* Compute relative timeout.  */ +      sec = abstime->tv_sec - tv.tv_sec; +      nsec = abstime->tv_nsec - tv.tv_usec * 1000; +      if (nsec < 0) +	{ +	  nsec += 1000000000; +	  --sec; +	} + +      /* Already timed out?  */ +      err = -ETIMEDOUT; +      if (sec < 0) +	{ +	  __set_errno (ETIMEDOUT); +	  err = -1; +	  break; +	} + +      /* Do wait.  */ +      rt.tv_sec = sec; +      rt.tv_nsec = nsec; + +      /* Enable asynchronous cancellation.  Required by the standard.  */ +      int oldtype = __pthread_enable_asynccancel (); + +      err = lll_futex_timed_wait (&isem->value, 0, &rt, +				  isem->private ^ FUTEX_PRIVATE_FLAG); + +      /* Disable asynchronous cancellation.  */ +      __pthread_disable_asynccancel (oldtype); + +      if (err != 0 && err != -EWOULDBLOCK) +	{ +	  __set_errno (-err); +	  err = -1; +	  break; +	} + +      if (__atomic_is_v9) +	val = atomic_decrement_if_positive (&isem->value); +      else +	{ +	  __sparc32_atomic_do_lock24 (&isem->lock); +	  val = isem->value; +	  if (val > 0) +	    isem->value = val - 1; +	  __sparc32_atomic_do_unlock24 (&isem->lock); +	} + +      if (val > 0) +	{ +	  err = 0; +	  break; +	} +    } + +  pthread_cleanup_pop (0); + +  if (__atomic_is_v9) +    atomic_decrement (&isem->nwaiters); +  else +    { +      __sparc32_atomic_do_lock24 (&isem->lock); +      isem->nwaiters--; +      __sparc32_atomic_do_unlock24 (&isem->lock); +    } + +  return err; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_trywait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_trywait.c new file mode 100644 index 000000000..d4e893805 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_trywait.c @@ -0,0 +1,54 @@ +/* sem_trywait -- wait on a semaphore.  SPARC version. +   Copyright (C) 2003, 2006, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <internaltypes.h> +#include <semaphore.h> + + +int +__new_sem_trywait (sem_t *sem) +{ +  struct sparc_old_sem *isem = (struct sparc_old_sem *) sem; +  int val; + +  if (isem->value > 0) +    { +      if (__atomic_is_v9) +	val = atomic_decrement_if_positive (&isem->value); +      else +	{ +	  __sparc32_atomic_do_lock24 (&isem->lock); +	  val = isem->value; +	  if (val > 0) +	    isem->value = val - 1; +	  __sparc32_atomic_do_unlock24 (&isem->lock); +	} +      if (val > 0) +	return 0; +    } + +  __set_errno (EAGAIN); +  return -1; +} +weak_alias(__new_sem_trywait, sem_trywait) + diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_wait.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_wait.c new file mode 100644 index 000000000..cfe04a802 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_wait.c @@ -0,0 +1,127 @@ +/* sem_wait -- wait on a semaphore.  Generic futex-using version. +   Copyright (C) 2003, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <internaltypes.h> +#include <semaphore.h> + +#include <pthreadP.h> + + +void +attribute_hidden +__sem_wait_cleanup (void *arg) +{ +  struct sparc_new_sem *isem = (struct sparc_new_sem *) arg; + +  if (__atomic_is_v9) +    atomic_decrement (&isem->nwaiters); +  else +    { +      __sparc32_atomic_do_lock24 (&isem->lock); +      isem->nwaiters--; +      __sparc32_atomic_do_unlock24 (&isem->lock); +    } +} + + +int +__new_sem_wait (sem_t *sem) +{ +  struct sparc_new_sem *isem = (struct sparc_new_sem *) sem; +  int err; +  int val; + +  if (__atomic_is_v9) +    val = atomic_decrement_if_positive (&isem->value); +  else +    { +      __sparc32_atomic_do_lock24 (&isem->lock); +      val = isem->value; +      if (val > 0) +	isem->value = val - 1; +      else +	isem->nwaiters++; +      __sparc32_atomic_do_unlock24 (&isem->lock); +    } + +  if (val > 0) +    return 0; + +  if (__atomic_is_v9) +    atomic_increment (&isem->nwaiters); +  else +    /* Already done above while still holding isem->lock.  */; + +  pthread_cleanup_push (__sem_wait_cleanup, isem); + +  while (1) +    { +      /* Enable asynchronous cancellation.  Required by the standard.  */ +      int oldtype = __pthread_enable_asynccancel (); + +      err = lll_futex_wait (&isem->value, 0, +			    isem->private ^ FUTEX_PRIVATE_FLAG); + +      /* Disable asynchronous cancellation.  */ +      __pthread_disable_asynccancel (oldtype); + +      if (err != 0 && err != -EWOULDBLOCK) +	{ +	  __set_errno (-err); +	  err = -1; +	  break; +	} + +      if (__atomic_is_v9) +	val = atomic_decrement_if_positive (&isem->value); +      else +	{ +	  __sparc32_atomic_do_lock24 (&isem->lock); +	  val = isem->value; +	  if (val > 0) +	    isem->value = val - 1; +	  __sparc32_atomic_do_unlock24 (&isem->lock); +	} + +      if (val > 0) +	{ +	  err = 0; +	  break; +	} +    } + +  pthread_cleanup_pop (0); + +  if (__atomic_is_v9) +    atomic_decrement (&isem->nwaiters); +  else +    { +      __sparc32_atomic_do_lock24 (&isem->lock); +      isem->nwaiters--; +      __sparc32_atomic_do_unlock24 (&isem->lock); +    } + +  return err; +} +weak_alias(__new_sem_wait, sem_wait) + diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h new file mode 100644 index 000000000..1f55bd623 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h @@ -0,0 +1,112 @@ +/* Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Jakub Jelinek <jakub@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <tls.h> +#include <sysdep.h> +#ifndef __ASSEMBLER__ +# include <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;					\ +	.globl		__syscall_error;	\ +ENTRY(name)					\ +	ld [%g7 + MULTIPLE_THREADS_OFFSET], %g1;\ +	cmp %g1, 0;				\ +	bne 1f;					\ +.type	__##syscall_name##_nocancel,@function;	\ +.globl	__##syscall_name##_nocancel;		\ +__##syscall_name##_nocancel:			\ +	 mov SYS_ify(syscall_name), %g1;	\ +	ta 0x10;				\ +	bcc 8f;					\ +	 mov %o7, %g1;				\ +	call __syscall_error;			\ +	 mov %g1, %o7;				\ +8:	jmpl %o7 + 8, %g0;			\ +	 nop;					\ +.size	__##syscall_name##_nocancel,.-__##syscall_name##_nocancel;\ +1:	save %sp, -96, %sp;			\ +	cfi_def_cfa_register(%fp);		\ +	cfi_window_save;			\ +	cfi_register(%o7, %i7);			\ +	CENABLE;				\ +	 nop;					\ +	mov %o0, %l0;				\ +	COPY_ARGS_##args			\ +	mov SYS_ify(syscall_name), %g1;		\ +	ta 0x10;				\ +	bcc 1f;					\ +	 mov %o0, %l1;				\ +	CDISABLE;				\ +	 mov %l0, %o0;				\ +	call __syscall_error;			\ +	 mov %l1, %o0;				\ +	b 2f;					\ +	 mov -1, %l1;				\ +1:	CDISABLE;				\ +	 mov %l0, %o0;				\ +2:	jmpl %i7 + 8, %g0;			\ +	 restore %g0, %l1, %o0; + + +# ifdef IS_IN_libpthread +#  define CENABLE	call __pthread_enable_asynccancel +#  define CDISABLE	call __pthread_disable_asynccancel +# elif !defined NOT_IN_libc +#  define CENABLE	call __libc_enable_asynccancel +#  define CDISABLE	call __libc_disable_asynccancel +# elif defined IS_IN_librt +#  define CENABLE	call __librt_enable_asynccancel +#  define CDISABLE	call __librt_disable_asynccancel +# else +#  error Unsupported library +# endif + +#define COPY_ARGS_0	/* Nothing */ +#define COPY_ARGS_1	COPY_ARGS_0 mov %i0, %o0; +#define COPY_ARGS_2	COPY_ARGS_1 mov %i1, %o1; +#define COPY_ARGS_3	COPY_ARGS_2 mov %i2, %o2; +#define COPY_ARGS_4	COPY_ARGS_3 mov %i3, %o3; +#define COPY_ARGS_5	COPY_ARGS_4 mov %i4, %o4; +#define COPY_ARGS_6	COPY_ARGS_5 mov %i5, %o5; + +# ifndef __ASSEMBLER__ +#  define SINGLE_THREAD_P \ +  __builtin_expect (THREAD_GETMEM (THREAD_SELF,				      \ +				   header.multiple_threads) == 0, 1) +# else +#  define SINGLE_THREAD_P ld [%g7 + MULTIPLE_THREADS_OFFSET], %g1 +# 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/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S new file mode 100644 index 000000000..8ee98684d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S @@ -0,0 +1,49 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + +   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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <tcb-offsets.h> + +	.text +	.globl		__syscall_error +ENTRY(__vfork) +	ld	[%g7 + PID], %o5 +	cmp	%o5, 0 +	bne	1f +	 sub	%g0, %o5, %o4 +	sethi	%hi(0x80000000), %o4 +1:	st	%o4, [%g7 + PID] + +	LOADSYSCALL(vfork) +	ta	0x10 +	bcc	2f +	 mov	%o7, %g1 +	st	%o5, [%g7 + PID] +	call	__syscall_error +	 mov	%g1, %o7 +2:	sub	%o1, 1, %o1 +	andcc	%o0, %o1, %o0 +	bne,a	1f +	 st	%o5, [%g7 + PID] +1:	retl +	 nop +END(__vfork) + +libc_hidden_def (vfork) +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S new file mode 100644 index 000000000..64e3bfc12 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S @@ -0,0 +1,2 @@ +#define RESET_PID +#include <libc/sysdeps/linux/sparc/sparcv9/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/pt-vfork.S new file mode 100644 index 000000000..8941043c3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/pt-vfork.S @@ -0,0 +1,45 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + +   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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <tcb-offsets.h> + +	.text +	.globl	__syscall_error +ENTRY(__vfork) +	ld	[%g7 + PID], %o5 +	sub	%g0, %o5, %o4 +	st	%o4, [%g7 + PID] + +	LOADSYSCALL(vfork) +	ta	0x6d +	bcc,pt	%xcc, 2f +	 mov	%o7, %g1 +	st	%o5, [%g7 + PID] +	call	__syscall_error +	 mov	%g1, %o7 +2:	sub	%o1, 1, %o1 +	andcc	%o0, %o1, %o0 +	bne,a,pt %icc, 1f +	 st	%o5, [%g7 + PID] +1:	retl +	 nop +END(__vfork) + +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h new file mode 100644 index 000000000..aec2d4a86 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h @@ -0,0 +1,110 @@ +/* Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Jakub Jelinek <jakub@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <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;					\ +	.globl		__syscall_error;	\ +ENTRY(name)					\ +	ld [%g7 + MULTIPLE_THREADS_OFFSET], %g1;\ +	brnz,pn %g1, 1f;			\ +.type	__##syscall_name##_nocancel,@function;	\ +.globl	__##syscall_name##_nocancel;		\ +__##syscall_name##_nocancel:			\ +	 mov SYS_ify(syscall_name), %g1;	\ +	ta 0x6d;				\ +	bcc,pt %xcc, 8f;			\ +	 mov %o7, %g1;				\ +	call __syscall_error;			\ +	 mov %g1, %o7;				\ +8:	jmpl %o7 + 8, %g0;			\ +	 nop;					\ +.size	__##syscall_name##_nocancel,.-__##syscall_name##_nocancel;\ +1:	save %sp, -192, %sp;			\ +	cfi_def_cfa_register(%fp);		\ +	cfi_window_save;			\ +	cfi_register(%o7, %i7);			\ +	CENABLE;				\ +	 nop;					\ +	mov %o0, %l0;				\ +	COPY_ARGS_##args			\ +	mov SYS_ify(syscall_name), %g1;		\ +	ta 0x6d;				\ +	bcc,pt %xcc, 1f;			\ +	 mov %o0, %l1;				\ +	CDISABLE;				\ +	 mov %l0, %o0;				\ +	call __syscall_error;			\ +	 mov %l1, %o0;				\ +	ba,pt %xcc, 2f;				\ +	 mov -1, %l1;				\ +1:	CDISABLE;				\ +	 mov %l0, %o0;				\ +2:	jmpl %i7 + 8, %g0;			\ +	 restore %g0, %l1, %o0; + +# ifdef IS_IN_libpthread +#  define CENABLE	call __pthread_enable_asynccancel +#  define CDISABLE	call __pthread_disable_asynccancel +# elif !defined NOT_IN_libc +#  define CENABLE	call __libc_enable_asynccancel +#  define CDISABLE	call __libc_disable_asynccancel +# elif defined IS_IN_librt +#  define CENABLE	call __librt_enable_asynccancel +#  define CDISABLE	call __librt_disable_asynccancel +# else +#  error Unsupported library +# endif + +#define COPY_ARGS_0	/* Nothing */ +#define COPY_ARGS_1	COPY_ARGS_0 mov %i0, %o0; +#define COPY_ARGS_2	COPY_ARGS_1 mov %i1, %o1; +#define COPY_ARGS_3	COPY_ARGS_2 mov %i2, %o2; +#define COPY_ARGS_4	COPY_ARGS_3 mov %i3, %o3; +#define COPY_ARGS_5	COPY_ARGS_4 mov %i4, %o4; +#define COPY_ARGS_6	COPY_ARGS_5 mov %i5, %o5; + +# ifndef __ASSEMBLER__ +#  define SINGLE_THREAD_P \ +  __builtin_expect (THREAD_GETMEM (THREAD_SELF,				      \ +				   header.multiple_threads) == 0, 1) +# else +#  define SINGLE_THREAD_P ld [%g7 + MULTIPLE_THREADS_OFFSET], %g1 +# 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/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_create.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_create.c new file mode 100644 index 000000000..0a9c3372b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_create.c @@ -0,0 +1 @@ +#include "../../x86_64/timer_create.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_delete.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_delete.c new file mode 100644 index 000000000..f0d4fd21d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_delete.c @@ -0,0 +1 @@ +#include "../../x86_64/timer_delete.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_getoverr.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_getoverr.c new file mode 100644 index 000000000..82121a7a2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_getoverr.c @@ -0,0 +1 @@ +#include "../../x86_64/timer_getoverr.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_gettime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_gettime.c new file mode 100644 index 000000000..313c05fea --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_gettime.c @@ -0,0 +1 @@ +#include "../../x86_64/timer_gettime.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_settime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_settime.c new file mode 100644 index 000000000..76f549cb4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/timer_settime.c @@ -0,0 +1 @@ +#include "../../x86_64/timer_settime.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S new file mode 100644 index 000000000..b4e89aceb --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S @@ -0,0 +1,49 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + +   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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <tcb-offsets.h> + +	.text +	.globl	__syscall_error +ENTRY(__vfork) +	ld	[%g7 + PID], %o5 +	sethi	%hi(0x80000000), %o3 +	cmp	%o5, 0 +	sub	%g0, %o5, %o4 +	move	%icc, %o3, %o4 +	st	%o4, [%g7 + PID] + +	LOADSYSCALL(vfork) +	ta	0x6d +	bcc,pt	%xcc, 2f +	 mov	%o7, %g1 +	st	%o5, [%g7 + PID] +	call	__syscall_error +	 mov	%g1, %o7 +2:	sub	%o1, 1, %o1 +	andcc	%o0, %o1, %o0 +	bne,a,pt %icc, 1f +	 st	%o5, [%g7 + PID] +1:	retl +	 nop +END(__vfork) + +hidden_def (vfork) +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep-cancel.h new file mode 100644 index 000000000..5be9beb92 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep-cancel.h @@ -0,0 +1,5 @@ +#if defined(__arch64__) +#include "sparc64/sysdep-cancel.h" +#else +#include "sparc32/sysdep-cancel.h" +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/vfork.S new file mode 100644 index 000000000..160cd0b10 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/vfork.S @@ -0,0 +1,5 @@ +#if defined(__arch64__) +#include "sparc64/vfork.S" +#else +#include "sparc32/vfork.S" +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/structsem.sym b/libpthread/nptl/sysdeps/unix/sysv/linux/structsem.sym new file mode 100644 index 000000000..0e2a15f2b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/structsem.sym @@ -0,0 +1,12 @@ +#include <limits.h> +#include <stddef.h> +#include <sched.h> +#include <bits/pthreadtypes.h> +#include "internaltypes.h" + +-- + +VALUE		offsetof (struct new_sem, value) +PRIVATE		offsetof (struct new_sem, private) +NWAITERS	offsetof (struct new_sem, nwaiters) +SEM_VALUE_MAX	SEM_VALUE_MAX diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_create.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_create.c new file mode 100644 index 000000000..a7da2a09a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_create.c @@ -0,0 +1,243 @@ +/* Copyright (C) 2003,2004, 2007, 2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sysdep.h> +#include <bits/kernel-features.h> +#include <internaltypes.h> +#include <pthreadP.h> +#include "kernel-posix-timers.h" +#include "kernel-posix-cpu-timers.h" + + +#ifdef __NR_timer_create +# ifndef __ASSUME_POSIX_TIMERS +static int compat_timer_create (clockid_t clock_id, struct sigevent *evp, +				timer_t *timerid); +#  define timer_create static compat_timer_create +#  include <nptl/sysdeps/pthread/timer_create.c> +#  undef timer_create + +/* Nonzero if the system calls are not available.  */ +int __no_posix_timers attribute_hidden; +# endif + +# ifdef timer_create_alias +#  define timer_create timer_create_alias +# endif + + +int +timer_create ( +     clockid_t clock_id, +     struct sigevent *evp, +     timer_t *timerid) +{ +# undef timer_create +# ifndef __ASSUME_POSIX_TIMERS +  if  (__no_posix_timers >= 0) +# endif +    { +      clockid_t syscall_clockid = (clock_id == CLOCK_PROCESS_CPUTIME_ID +				   ? MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED) +				   : clock_id == CLOCK_THREAD_CPUTIME_ID +				   ? MAKE_THREAD_CPUCLOCK (0, CPUCLOCK_SCHED) +				   : clock_id); + +      /* If the user wants notification via a thread we need to handle +	 this special.  */ +      if (evp == NULL +	  || __builtin_expect (evp->sigev_notify != SIGEV_THREAD, 1)) +	{ +	  struct sigevent local_evp; + +	  /* We avoid allocating too much memory by basically +	     using struct timer as a derived class with the +	     first two elements being in the superclass.  We only +	     need these two elements here.  */ +	  struct timer *newp = (struct timer *) malloc (offsetof (struct timer, +								  thrfunc)); +	  if (newp == NULL) +	    /* No more memory.  */ +	    return -1; + +	  if (evp == NULL) +	    { +	      /* The kernel has to pass up the timer ID which is a +		 userlevel object.  Therefore we cannot leave it up to +		 the kernel to determine it.  */ +	      local_evp.sigev_notify = SIGEV_SIGNAL; +	      local_evp.sigev_signo = SIGALRM; +	      local_evp.sigev_value.sival_ptr = newp; + +	      evp = &local_evp; +	    } + +	  kernel_timer_t ktimerid; +	  int retval = INLINE_SYSCALL (timer_create, 3, syscall_clockid, evp, +				       &ktimerid); + +# ifndef __ASSUME_POSIX_TIMERS +	  if (retval != -1 || errno != ENOSYS) +# endif +	    { +# ifndef __ASSUME_POSIX_TIMERS +	      __no_posix_timers = 1; +# endif + +	      if (retval != -1) +		{ +		  newp->sigev_notify = (evp != NULL +					? evp->sigev_notify : SIGEV_SIGNAL); +		  newp->ktimerid = ktimerid; + +		  *timerid = (timer_t) newp; +		} +	      else +		{ +		  /* Cannot allocate the timer, fail.  */ +		  free (newp); +		  retval = -1; +		} + +	      return retval; +	    } + +	  free (newp); + +# ifndef __ASSUME_POSIX_TIMERS +	  /* When we come here the syscall does not exist.  Make sure we +	     do not try to use it again.  */ +	  __no_posix_timers = -1; +# endif +	} +      else +	{ +# ifndef __ASSUME_POSIX_TIMERS +	  /* Make sure we have the necessary kernel support.  */ +	  if (__no_posix_timers == 0) +	    { +	      INTERNAL_SYSCALL_DECL (err); +	      struct timespec ts; +	      int res; +	      res = INTERNAL_SYSCALL (clock_getres, err, 2, +				      CLOCK_REALTIME, &ts); +	      __no_posix_timers = (INTERNAL_SYSCALL_ERROR_P (res, err) +				   ? -1 : 1); +	    } + +	  if (__no_posix_timers > 0) +# endif +	    { +	      /* Create the helper thread.  */ +	      pthread_once (&__helper_once, __start_helper_thread); +	      if (__helper_tid == 0) +		{ +		  /* No resources to start the helper thread.  */ +		  __set_errno (EAGAIN); +		  return -1; +		} + +	      struct timer *newp; +	      newp = (struct timer *) malloc (sizeof (struct timer)); +	      if (newp == NULL) +		return -1; + +	      /* Copy the thread parameters the user provided.  */ +	      newp->sival = evp->sigev_value; +	      newp->thrfunc = evp->sigev_notify_function; +	      newp->sigev_notify = SIGEV_THREAD; + +	      /* We cannot simply copy the thread attributes since the +		 implementation might keep internal information for +		 each instance.  */ +	      (void) pthread_attr_init (&newp->attr); +	      if (evp->sigev_notify_attributes != NULL) +		{ +		  struct pthread_attr *nattr; +		  struct pthread_attr *oattr; + +		  nattr = (struct pthread_attr *) &newp->attr; +		  oattr = (struct pthread_attr *) evp->sigev_notify_attributes; + +		  nattr->schedparam = oattr->schedparam; +		  nattr->schedpolicy = oattr->schedpolicy; +		  nattr->flags = oattr->flags; +		  nattr->guardsize = oattr->guardsize; +		  nattr->stackaddr = oattr->stackaddr; +		  nattr->stacksize = oattr->stacksize; +		} + +	      /* In any case set the detach flag.  */ +	      (void) pthread_attr_setdetachstate (&newp->attr, +						  PTHREAD_CREATE_DETACHED); + +	      /* Create the event structure for the kernel timer.  */ +	      struct sigevent sev = +		{ .sigev_value.sival_ptr = newp, +		  .sigev_signo = SIGTIMER, +		  .sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID, +		  ._sigev_un = { ._pad = { [0] = __helper_tid } } }; + +	      /* Create the timer.  */ +	      INTERNAL_SYSCALL_DECL (err); +	      int res; +	      res = INTERNAL_SYSCALL (timer_create, err, 3, +				      syscall_clockid, &sev, &newp->ktimerid); +	      if (! INTERNAL_SYSCALL_ERROR_P (res, err)) +		{ +		  /* Add to the queue of active timers with thread +		     delivery.  */ +		  pthread_mutex_lock (&__active_timer_sigev_thread_lock); +		  newp->next = __active_timer_sigev_thread; +		  __active_timer_sigev_thread = newp; +		  pthread_mutex_unlock (&__active_timer_sigev_thread_lock); + +		  *timerid = (timer_t) newp; +		  return 0; +		} + +	      /* Free the resources.  */ +	      free (newp); + +	      __set_errno (INTERNAL_SYSCALL_ERRNO (res, err)); + +	      return -1; +	    } +	} +    } + +# ifndef __ASSUME_POSIX_TIMERS +  /* Compatibility code.  */ +  return compat_timer_create (clock_id, evp, timerid); +# endif +} +#else +# ifdef timer_create_alias +#  define timer_create timer_create_alias +# endif +/* The new system calls are not available.  Use the userlevel +   implementation.  */ +# include <nptl/sysdeps/pthread/timer_create.c> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_delete.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_delete.c new file mode 100644 index 000000000..5ad40b99a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_delete.c @@ -0,0 +1,115 @@ +/* Copyright (C) 2003, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +#include <errno.h> +#include <stdlib.h> +#include <time.h> +#include <sysdep.h> +#include <bits/kernel-features.h> +#include "kernel-posix-timers.h" + + +#ifdef __NR_timer_delete +# ifndef __ASSUME_POSIX_TIMERS +static int compat_timer_delete (timer_t timerid); +#  define timer_delete static compat_timer_delete +#  include <nptl/sysdeps/pthread/timer_delete.c> +#  undef timer_delete +# endif + +# ifdef timer_delete_alias +#  define timer_delete timer_delete_alias +# endif + + +int +timer_delete ( +     timer_t timerid) +{ +# undef timer_delete +# ifndef __ASSUME_POSIX_TIMERS +  if (__no_posix_timers >= 0) +# endif +    { +      struct timer *kt = (struct timer *) timerid; + +      /* Delete the kernel timer object.  */ +      int res = INLINE_SYSCALL (timer_delete, 1, kt->ktimerid); + +      if (res == 0) +	{ +	  if (kt->sigev_notify == SIGEV_THREAD) +	    { +	      /* Remove the timer from the list.  */ +	      pthread_mutex_lock (&__active_timer_sigev_thread_lock); +	      if (__active_timer_sigev_thread == kt) +		__active_timer_sigev_thread = kt->next; +	      else +		{ +		  struct timer *prevp = __active_timer_sigev_thread; +		  while (prevp->next != NULL) +		    if (prevp->next == kt) +		      { +			prevp->next = kt->next; +			break; +		      } +		    else +		      prevp = prevp->next; +		} +	      pthread_mutex_unlock (&__active_timer_sigev_thread_lock); +	    } + +# ifndef __ASSUME_POSIX_TIMERS +	  /* We know the syscall support is available.  */ +	  __no_posix_timers = 1; +# endif + +	  /* Free the memory.  */ +	  (void) free (kt); + +	  return 0; +	} + +      /* The kernel timer is not known or something else bad happened. +	 Return the error.  */ +# ifndef __ASSUME_POSIX_TIMERS +      if (errno != ENOSYS) +	{ +	  __no_posix_timers = 1; +# endif +	  return -1; +# ifndef __ASSUME_POSIX_TIMERS +	} + +      __no_posix_timers = -1; +# endif +    } + +# ifndef __ASSUME_POSIX_TIMERS +  return compat_timer_delete (timerid); +# endif +} +#else +# ifdef timer_delete_alias +#  define timer_delete timer_delete_alias +# endif +/* The new system calls are not available.  Use the userlevel +   implementation.  */ +# include <nptl/sysdeps/pthread/timer_delete.c> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_getoverr.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_getoverr.c new file mode 100644 index 000000000..62a558aef --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_getoverr.c @@ -0,0 +1,81 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +#include <errno.h> +#include <time.h> +#include <sysdep.h> +#include <bits/kernel-features.h> +#include "kernel-posix-timers.h" + + +#ifdef __NR_timer_getoverrun +# ifndef __ASSUME_POSIX_TIMERS +static int compat_timer_getoverrun (timer_t timerid); +#  define timer_getoverrun static compat_timer_getoverrun +#  include <nptl/sysdeps/pthread/timer_getoverr.c> +#  undef timer_getoverrun +# endif + +# ifdef timer_getoverrun_alias +#  define timer_getoverrun timer_getoverrun_alias +# endif + + +int +timer_getoverrun ( +     timer_t timerid) +{ +# undef timer_getoverrun +# ifndef __ASSUME_POSIX_TIMERS +  if (__no_posix_timers >= 0) +# endif +    { +      struct timer *kt = (struct timer *) timerid; + +      /* Get the information from the kernel.  */ +      int res = INLINE_SYSCALL (timer_getoverrun, 1, kt->ktimerid); + +# ifndef __ASSUME_POSIX_TIMERS +      if (res != -1 || errno != ENOSYS) +	{ +	  /* We know the syscall support is available.  */ +	  __no_posix_timers = 1; +# endif +	  return res; +# ifndef __ASSUME_POSIX_TIMERS +	} +# endif + +# ifndef __ASSUME_POSIX_TIMERS +      __no_posix_timers = -1; +# endif +    } + +# ifndef __ASSUME_POSIX_TIMERS +  return compat_timer_getoverrun (timerid); +# endif +} +#else +# ifdef timer_getoverrun_alias +#  define timer_getoverrun timer_getoverrun_alias +# endif +/* The new system calls are not available.  Use the userlevel +   implementation.  */ +# include <nptl/sysdeps/pthread/timer_getoverr.c> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_gettime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_gettime.c new file mode 100644 index 000000000..31401b19b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_gettime.c @@ -0,0 +1,83 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +#include <errno.h> +#include <stdlib.h> +#include <time.h> +#include <sysdep.h> +#include <bits/kernel-features.h> +#include "kernel-posix-timers.h" + + +#ifdef __NR_timer_gettime +# ifndef __ASSUME_POSIX_TIMERS +static int compat_timer_gettime (timer_t timerid, struct itimerspec *value); +#  define timer_gettime static compat_timer_gettime +#  include <nptl/sysdeps/pthread/timer_gettime.c> +#  undef timer_gettime +# endif + +# ifdef timer_gettime_alias +#  define timer_gettime timer_gettime_alias +# endif + + +int +timer_gettime ( +     timer_t timerid, +     struct itimerspec *value) +{ +# undef timer_gettime +# ifndef __ASSUME_POSIX_TIMERS +  if (__no_posix_timers >= 0) +# endif +    { +      struct timer *kt = (struct timer *) timerid; + +      /* Delete the kernel timer object.  */ +      int res = INLINE_SYSCALL (timer_gettime, 2, kt->ktimerid, value); + +# ifndef __ASSUME_POSIX_TIMERS +      if (res != -1 || errno != ENOSYS) +	{ +	  /* We know the syscall support is available.  */ +	  __no_posix_timers = 1; +# endif +	  return res; +# ifndef __ASSUME_POSIX_TIMERS +	} +# endif + +# ifndef __ASSUME_POSIX_TIMERS +      __no_posix_timers = -1; +# endif +    } + +# ifndef __ASSUME_POSIX_TIMERS +  return compat_timer_gettime (timerid, value); +# endif +} +#else +# ifdef timer_gettime_alias +#  define timer_gettime timer_gettime_alias +# endif +/* The new system calls are not available.  Use the userlevel +   implementation.  */ +# include <nptl/sysdeps/pthread/timer_gettime.c> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_routines.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_routines.c new file mode 100644 index 000000000..2681961bf --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_routines.c @@ -0,0 +1,204 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +#include <errno.h> +#include <setjmp.h> +#include <signal.h> +#include <stdbool.h> +#include <sysdep.h> +#include <bits/kernel-features.h> +#include <pthreadP.h> +#include "kernel-posix-timers.h" + + +/* List of active SIGEV_THREAD timers.  */ +struct timer *__active_timer_sigev_thread; +/* Lock for the __active_timer_sigev_thread.  */ +pthread_mutex_t __active_timer_sigev_thread_lock = PTHREAD_MUTEX_INITIALIZER; + + +struct thread_start_data +{ +  void (*thrfunc) (sigval_t); +  sigval_t sival; +}; + + +#ifdef __NR_timer_create +/* Helper thread to call the user-provided function.  */ +static void * +timer_sigev_thread (void *arg) +{ +  /* The parent thread has all signals blocked.  This is a bit +     surprising for user code, although valid.  We unblock all +     signals.  */ +  sigset_t ss; +  sigemptyset (&ss); +  INTERNAL_SYSCALL_DECL (err); +  INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &ss, NULL, _NSIG / 8); + +  struct thread_start_data *td = (struct thread_start_data *) arg; + +  void (*thrfunc) (sigval_t) = td->thrfunc; +  sigval_t sival = td->sival; + +  /* The TD object was allocated in timer_helper_thread.  */ +  free (td); + +  /* Call the user-provided function.  */ +  thrfunc (sival); + +  return NULL; +} + + +/* Helper function to support starting threads for SIGEV_THREAD.  */ +static void * +timer_helper_thread (void *arg) +{ +  /* Wait for the SIGTIMER signal, allowing the setXid signal, and +     none else.  */ +  sigset_t ss; +  sigemptyset (&ss); +  __sigaddset (&ss, SIGTIMER); + +  /* Endless loop of waiting for signals.  The loop is only ended when +     the thread is canceled.  */ +  while (1) +    { +      siginfo_t si; + +      /* sigwaitinfo cannot be used here, since it deletes +	 SIGCANCEL == SIGTIMER from the set.  */ + +      int oldtype = LIBC_CANCEL_ASYNC (); + +      /* XXX The size argument hopefully will have to be changed to the +	 real size of the user-level sigset_t.  */ +      int result = INLINE_SYSCALL (rt_sigtimedwait, 4, &ss, &si, NULL, +				   _NSIG / 8); + +      LIBC_CANCEL_RESET (oldtype); + +      if (result > 0) +	{ +	  if (si.si_code == SI_TIMER) +	    { +	      struct timer *tk = (struct timer *) si.si_ptr; + +	      /* Check the timer is still used and will not go away +		 while we are reading the values here.  */ +	      pthread_mutex_lock (&__active_timer_sigev_thread_lock); + +	      struct timer *runp = __active_timer_sigev_thread; +	      while (runp != NULL) +		if (runp == tk) +		  break; +		else +		  runp = runp->next; + +	      if (runp != NULL) +		{ +		  struct thread_start_data *td = malloc (sizeof (*td)); + +		  /* There is not much we can do if the allocation fails.  */ +		  if (td != NULL) +		    { +		      /* This is the signal we are waiting for.  */ +		      td->thrfunc = tk->thrfunc; +		      td->sival = tk->sival; + +		      pthread_t th; +		      (void) pthread_create (&th, &tk->attr, +					     timer_sigev_thread, td); +		    } +		} + +	      pthread_mutex_unlock (&__active_timer_sigev_thread_lock); +	    } +	  else if (si.si_code == SI_TKILL) +	    /* The thread is canceled.  */ +	    pthread_exit (NULL); +	} +    } +} + + +/* Control variable for helper thread creation.  */ +pthread_once_t __helper_once attribute_hidden; + + +/* TID of the helper thread.  */ +pid_t __helper_tid attribute_hidden; + + +/* Reset variables so that after a fork a new helper thread gets started.  */ +static void +reset_helper_control (void) +{ +  __helper_once = PTHREAD_ONCE_INIT; +  __helper_tid = 0; +} + + +void +attribute_hidden +__start_helper_thread (void) +{ +  /* The helper thread needs only very little resources +     and should go away automatically when canceled.  */ +  pthread_attr_t attr; +  (void) pthread_attr_init (&attr); +  (void) pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN); + +  /* Block all signals in the helper thread but SIGSETXID.  To do this +     thoroughly we temporarily have to block all signals here.  The +     helper can lose wakeups if SIGCANCEL is not blocked throughout, +     but sigfillset omits it SIGSETXID.  So, we add SIGCANCEL back +     explicitly here.  */ +  sigset_t ss; +  sigset_t oss; +  sigfillset (&ss); +  __sigaddset (&ss, SIGCANCEL); +  INTERNAL_SYSCALL_DECL (err); +  INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &ss, &oss, _NSIG / 8); + +  /* Create the helper thread for this timer.  */ +  pthread_t th; +  int res = pthread_create (&th, &attr, timer_helper_thread, NULL); +  if (res == 0) +    /* We managed to start the helper thread.  */ +    __helper_tid = ((struct pthread *) th)->tid; + +  /* Restore the signal mask.  */ +  INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &oss, NULL, +		    _NSIG / 8); + +  /* No need for the attribute anymore.  */ +  (void) pthread_attr_destroy (&attr); + +  /* We have to make sure that after fork()ing a new helper thread can +     be created.  */ +  pthread_atfork (NULL, NULL, reset_helper_control); +} +#endif + +#ifndef __ASSUME_POSIX_TIMERS +# include <nptl/sysdeps/pthread/timer_routines.c> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/timer_settime.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_settime.c new file mode 100644 index 000000000..8c6ad91fa --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_settime.c @@ -0,0 +1,88 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +#include <errno.h> +#include <stdlib.h> +#include <time.h> +#include <sysdep.h> +#include <bits/kernel-features.h> +#include "kernel-posix-timers.h" + + +#ifdef __NR_timer_settime +# ifndef __ASSUME_POSIX_TIMERS +static int compat_timer_settime (timer_t timerid, int flags, +				 const struct itimerspec *value, +				 struct itimerspec *ovalue); +#  define timer_settime static compat_timer_settime +#  include <nptl/sysdeps/pthread/timer_settime.c> +#  undef timer_settime +# endif + +# ifdef timer_settime_alias +#  define timer_settime timer_settime_alias +# endif + + +int +timer_settime ( +     timer_t timerid, +     int flags, +     const struct itimerspec *value, +     struct itimerspec *ovalue) +{ +# undef timer_settime +# ifndef __ASSUME_POSIX_TIMERS +  if (__no_posix_timers >= 0) +# endif +    { +      struct timer *kt = (struct timer *) timerid; + +      /* Delete the kernel timer object.  */ +      int res = INLINE_SYSCALL (timer_settime, 4, kt->ktimerid, flags, +				value, ovalue); + +# ifndef __ASSUME_POSIX_TIMERS +      if (res != -1 || errno != ENOSYS) +	{ +	  /* We know the syscall support is available.  */ +	  __no_posix_timers = 1; +# endif +	  return res; +# ifndef __ASSUME_POSIX_TIMERS +	} +# endif + +# ifndef __ASSUME_POSIX_TIMERS +      __no_posix_timers = -1; +# endif +    } + +# ifndef __ASSUME_POSIX_TIMERS +  return compat_timer_settime (timerid, flags, value, ovalue); +# endif +} +#else +# ifdef timer_settime_alias +#  define timer_settime timer_settime_alias +# endif +/* The new system calls are not available.  Use the userlevel +   implementation.  */ +# include <nptl/sysdeps/pthread/timer_settime.c> +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c new file mode 100644 index 000000000..7eb095fd3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c @@ -0,0 +1,123 @@ +/* Copyright (C) 2002, 2003, 2005, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include <stdlib.h> +#include <fork.h> +#include <atomic.h> +#include <tls.h> + + +void +__unregister_atfork ( +     void *dso_handle) +{ +  /* Check whether there is any entry in the list which we have to +     remove.  It is likely that this is not the case so don't bother +     getting the lock. + +     We do not worry about other threads adding entries for this DSO +     right this moment.  If this happens this is a race and we can do +     whatever we please.  The program will crash anyway seen.  */ +  struct fork_handler *runp = __fork_handlers; +  struct fork_handler *lastp = NULL; + +  while (runp != NULL) +    if (runp->dso_handle == dso_handle) +      break; +    else +      { +	lastp = runp; +	runp = runp->next; +      } + +  if (runp == NULL) +    /* Nothing to do.  */ +    return; + +  /* Get the lock to not conflict with additions or deletions.  Note +     that there couldn't have been another thread deleting something. +     The __unregister_atfork function is only called from the +     dlclose() code which itself serializes the operations.  */ +  lll_lock (__fork_lock, LLL_PRIVATE); + +  /* We have to create a new list with all the entries we don't remove.  */ +  struct deleted_handler +  { +    struct fork_handler *handler; +    struct deleted_handler *next; +  } *deleted = NULL; + +  /* Remove the entries for the DSO which is unloaded from the list. +     It's a single linked list so readers are.  */ +  do +    { +    again: +      if (runp->dso_handle == dso_handle) +	{ +	  if (lastp == NULL) +	    { +	      /* We have to use an atomic operation here because +		 __linkin_atfork also uses one.  */ +	      if (catomic_compare_and_exchange_bool_acq (&__fork_handlers, +							 runp->next, runp) +		  != 0) +		{ +		  runp = __fork_handlers; +		  goto again; +		} +	    } +	  else +	    lastp->next = runp->next; + +	  /* We cannot overwrite the ->next element now.  Put the deleted +	     entries in a separate list.  */ +	  struct deleted_handler *newp = alloca (sizeof (*newp)); +	  newp->handler = runp; +	  newp->next = deleted; +	  deleted = newp; +	} +      else +	lastp = runp; + +      runp = runp->next; +    } +  while (runp != NULL); + +  /* Release the lock.  */ +  lll_unlock (__fork_lock, LLL_PRIVATE); + +  /* Walk the list of all entries which have to be deleted.  */ +  while (deleted != NULL) +    { +      /* We need to be informed by possible current users.  */ +      deleted->handler->need_signal = 1; +      /* Make sure this gets written out first.  */ +      atomic_write_barrier (); + +      /* Decrement the reference counter.  If it does not reach zero +	 wait for the last user.  */ +      atomic_decrement (&deleted->handler->refcntr); +      unsigned int val; +      while ((val = deleted->handler->refcntr) != 0) +	lll_futex_wait (&deleted->handler->refcntr, val, LLL_PRIVATE); + +      deleted = deleted->next; +    } +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/unwindbuf.sym b/libpthread/nptl/sysdeps/unix/sysv/linux/unwindbuf.sym new file mode 100644 index 000000000..8044b4078 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/unwindbuf.sym @@ -0,0 +1,7 @@ +#include <pthread.h> +#include <stddef.h> + +-- + +UNWINDBUFSIZE	sizeof (__pthread_unwind_buf_t) +UWJMPBUF	offsetof (__pthread_unwind_buf_t, __cancel_jmp_buf) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/waitpid.S b/libpthread/nptl/sysdeps/unix/sysv/linux/waitpid.S new file mode 100644 index 000000000..f55d34629 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/waitpid.S @@ -0,0 +1,19 @@ +#include <sysdep-cancel.h> + +/* +extern pid_t __waitpid_nocancel (pid_t, int *, int) attribute_hidden; +*/ +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + + +PSEUDO (__waitpid, waitpid, 3) +ret +PSEUDO_END(__waitpid) + +libc_hidden_def (__waitpid) +weak_alias (__waitpid, waitpid) +libc_hidden_weak (waitpid) +weak_alias (__waitpid, __libc_waitpid) +libc_hidden_weak (__libc_waitpid) + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/write.S b/libpthread/nptl/sysdeps/unix/sysv/linux/write.S new file mode 100644 index 000000000..43de3320d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/write.S @@ -0,0 +1,19 @@ +#include <sysdep-cancel.h> + +/* +extern int __write_nocancel (int, const void *, size_t) attribute_hidden; +*/ +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +PSEUDO (__libc_write, write, 3) +ret +PSEUDO_END(__libc_write) + +libc_hidden_def (__write_nocancel) +libc_hidden_def (__libc_write) +weak_alias (__libc_write, __write) +libc_hidden_weak (__write) +weak_alias (__libc_write, write) +libc_hidden_weak (write) + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Makefile new file mode 100644 index 000000000..43a6fad84 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../../../../ +top_builddir=../../../../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.arch +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Makefile.arch new file mode 100644 index 000000000..53a87728f --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Makefile.arch @@ -0,0 +1,78 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# +LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/x86_64 +LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/x86_64 + + +libpthread_SSRC = pt-vfork.S clone.S pthread_once.S +libpthread_CSRC = pthread_spin_init.c pt-__syscall_error.c + +libc_a_CSRC = fork.c +libc_a_SSRC = clone.S vfork.S + +libpthread_SSRC += lowlevellock.S pthread_barrier_wait.S pthread_cond_signal.S pthread_cond_broadcast.S \ +		   sem_post.S sem_timedwait.S lowlevelrobustlock.S \ +		   sem_trywait.S sem_wait.S pthread_rwlock_rdlock.S pthread_rwlock_wrlock.S \ +		   pthread_rwlock_timedrdlock.S pthread_rwlock_timedwrlock.S pthread_rwlock_unlock.S \ +		   pthread_spin_unlock.S +# pthread_cond_timedwait.S pthread_cond_wait.S +libc_a_SSRC += libc-lowlevellock.S + + +CFLAGS-OMIT-fork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-pt-__syscall_error.c =  -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y) +CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__ +endif + +ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-lowlevellock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD +ASFLAGS-pthread_once.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD + + +ASFLAGS-clone.S = -D_LIBC_REENTRANT +ASFLAGS-vfork.S = -D_LIBC_REENTRANT +ASFLAGS-libc-lowlevellock.S = -D_LIBC_REENTRANT + +ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) +#Needed to use the correct SYSCALL_ERROR_HANDLER +ASFLAGS-clone.S += -DUSE___THREAD +ASFLAGS-vfork.S += -DUSE___THREAD +ASFLAGS-sem_wait.S += -DUSE___THREAD +ASFLAGS-sem_trywait.S += -DUSE___THREAD +ASFLAGS-sem_timedwait.S += -DUSE___THREAD +ASFLAGS-sem_post.S += -DUSE___THREAD +endif + +CFLAGS += $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +LINUX_ARCH_OBJ:=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libpthread_SSRC)) +LINUX_ARCH_OBJ+=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(LINUX_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(LINUX_ARCH_OBJ) +endif +libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y+=$(LINUX_ARCH_OBJS) + +LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC)) +LIBC_LINUX_ARCH_OBJ+=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libc_a_SSRC)) + +libc-static-y+=$(LIBC_LINUX_ARCH_OBJ) +libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS) + +libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ) + +objclean-y+=nptl_linux_arch_clean + +nptl_linux_arch_clean: +	$(do_rm) $(addprefix $(LINUX_ARCH_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h new file mode 100644 index 000000000..7a09c8119 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h @@ -0,0 +1,225 @@ +/* Copyright (C) 2002,2003,2004,2005,2006,2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H	1 + +#include <bits/wordsize.h> + +#if __WORDSIZE == 64 +# define __SIZEOF_PTHREAD_ATTR_T 56 +# define __SIZEOF_PTHREAD_MUTEX_T 40 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 56 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 32 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#else +# define __SIZEOF_PTHREAD_ATTR_T 36 +# define __SIZEOF_PTHREAD_MUTEX_T 24 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 32 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 20 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#endif + + +/* Thread identifiers.  The structure of the attribute type is not +   exposed on purpose.  */ +typedef unsigned long int pthread_t; + + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_ATTR_T]; +  long int __align; +} pthread_attr_t; + + +#if __WORDSIZE == 64 +typedef struct __pthread_internal_list +{ +  struct __pthread_internal_list *__prev; +  struct __pthread_internal_list *__next; +} __pthread_list_t; +#else +typedef struct __pthread_internal_slist +{ +  struct __pthread_internal_slist *__next; +} __pthread_slist_t; +#endif + + +/* Data structures for mutex handling.  The structure of the attribute +   type is not exposed on purpose.  */ +typedef union +{ +  struct __pthread_mutex_s +  { +    int __lock; +    unsigned int __count; +    int __owner; +#if __WORDSIZE == 64 +    unsigned int __nusers; +#endif +    /* KIND must stay at this position in the structure to maintain +       binary compatibility.  */ +    int __kind; +#if __WORDSIZE == 64 +    int __spins; +    __pthread_list_t __list; +# define __PTHREAD_MUTEX_HAVE_PREV	1 +#else +    unsigned int __nusers; +    __extension__ union +    { +      int __spins; +      __pthread_slist_t __list; +    }; +#endif +  } __data; +  char __size[__SIZEOF_PTHREAD_MUTEX_T]; +  long int __align; +} pthread_mutex_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; +  int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling.  The structure of +   the attribute type is not exposed on purpose.  */ +typedef union +{ +  struct +  { +    int __lock; +    unsigned int __futex; +    __extension__ unsigned long long int __total_seq; +    __extension__ unsigned long long int __wakeup_seq; +    __extension__ unsigned long long int __woken_seq; +    void *__mutex; +    unsigned int __nwaiters; +    unsigned int __broadcast_seq; +  } __data; +  char __size[__SIZEOF_PTHREAD_COND_T]; +  __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_CONDATTR_T]; +  int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling.  The +   structure of the attribute type is not exposed on purpose.  */ +typedef union +{ +# if __WORDSIZE == 64 +  struct +  { +    int __lock; +    unsigned int __nr_readers; +    unsigned int __readers_wakeup; +    unsigned int __writer_wakeup; +    unsigned int __nr_readers_queued; +    unsigned int __nr_writers_queued; +    int __writer; +    int __shared; +    unsigned long int __pad1; +    unsigned long int __pad2; +    /* FLAGS must stay at this position in the structure to maintain +       binary compatibility.  */ +    unsigned int __flags; +  } __data; +# else +  struct +  { +    int __lock; +    unsigned int __nr_readers; +    unsigned int __readers_wakeup; +    unsigned int __writer_wakeup; +    unsigned int __nr_readers_queued; +    unsigned int __nr_writers_queued; +    /* FLAGS must stay at this position in the structure to maintain +       binary compatibility.  */ +    unsigned char __flags; +    unsigned char __shared; +    unsigned char __pad1; +    unsigned char __pad2; +    int __writer; +  } __data; +# endif +  char __size[__SIZEOF_PTHREAD_RWLOCK_T]; +  long int __align; +} pthread_rwlock_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; +  long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type.  */ +typedef volatile int pthread_spinlock_t; + + +/* POSIX barriers data type.  The structure of the type is +   deliberately not exposed.  */ +typedef union +{ +  char __size[__SIZEOF_PTHREAD_BARRIER_T]; +  long int __align; +} pthread_barrier_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; +  int __align; +} pthread_barrierattr_t; +#endif + + +#if __WORDSIZE == 32 +/* Extra attributes for the cleanup functions.  */ +# define __cleanup_fct_attribute __attribute__ ((__regparm__ (1))) +#endif + +#endif	/* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h new file mode 100644 index 000000000..e973bc5bf --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h @@ -0,0 +1,41 @@ +/* Copyright (C) 2002, 2004 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + +#include <bits/wordsize.h> + +#if __WORDSIZE == 64 +# define __SIZEOF_SEM_T	32 +#else +# define __SIZEOF_SEM_T	16 +#endif + + +/* Value returned if `sem_open' failed.  */ +#define SEM_FAILED      ((sem_t *) 0) + + +typedef union +{ +  char __size[__SIZEOF_SEM_T]; +  long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/cancellation.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/cancellation.S new file mode 100644 index 000000000..680696200 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/cancellation.S @@ -0,0 +1,116 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2009. + +   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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <tcb-offsets.h> +#include <kernel-features.h> +#include "lowlevellock.h" + +#ifdef IS_IN_libpthread +# ifdef SHARED +#  define __pthread_unwind __GI___pthread_unwind +# endif +#else +# ifndef SHARED +	.weak __pthread_unwind +# endif +#endif + + +#ifdef __ASSUME_PRIVATE_FUTEX +# define LOAD_PRIVATE_FUTEX_WAIT(reg) \ +	movl	$(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg +#else +# if FUTEX_WAIT == 0 +#  define LOAD_PRIVATE_FUTEX_WAIT(reg) \ +	movl	%fs:PRIVATE_FUTEX, reg +# else +#  define LOAD_PRIVATE_FUTEX_WAIT(reg) \ +	movl	%fs:PRIVATE_FUTEX, reg ; \ +	orl	$FUTEX_WAIT, reg +# endif +#endif + +/* It is crucial that the functions in this file don't modify registers +   other than %rax and %r11.  The syscall wrapper code depends on this +   because it doesn't explicitly save the other registers which hold +   relevant values.  */ +	.text + +	.hidden __pthread_enable_asynccancel +ENTRY(__pthread_enable_asynccancel) +	movl	%fs:CANCELHANDLING, %eax +2:	movl	%eax, %r11d +	orl	$TCB_CANCELTYPE_BITMASK, %r11d +	cmpl	%eax, %r11d +	je	1f + +	lock +	cmpxchgl %r11d, %fs:CANCELHANDLING +	jnz	2b + +	andl	$(TCB_CANCELSTATE_BITMASK|TCB_CANCELTYPE_BITMASK|TCB_CANCELED_BITMASK|TCB_EXITING_BITMASK|TCB_CANCEL_RESTMASK|TCB_TERMINATED_BITMASK), %r11d +	cmpl	$(TCB_CANCELTYPE_BITMASK|TCB_CANCELED_BITMASK), %r11d +	je	3f + +1:	ret + +3:	movq	$TCB_PTHREAD_CANCELED, %fs:RESULT +	lock +	orl	$TCB_EXITING_BITMASK, %fs:CANCELHANDLING +	movq	%fs:CLEANUP_JMP_BUF, %rdi +#ifdef SHARED +	call	__pthread_unwind@PLT +#else +	call	__pthread_unwind +#endif +	hlt +END(__pthread_enable_asynccancel) + + +	.hidden __pthread_disable_asynccancel +ENTRY(__pthread_disable_asynccancel) +	testl	$TCB_CANCELTYPE_BITMASK, %edi +	jnz	1f + +	movl	%fs:CANCELHANDLING, %eax +2:	movl	%eax, %r11d +	andl	$~TCB_CANCELTYPE_BITMASK, %r11d +	lock +	cmpxchgl %r11d, %fs:CANCELHANDLING +	jnz	2b + +	movl	%r11d, %eax +3:	andl	$(TCB_CANCELING_BITMASK|TCB_CANCELED_BITMASK), %eax +	cmpl	$TCB_CANCELING_BITMASK, %eax +	je	4f +1:	ret + +	/* Performance doesn't matter in this loop.  We will +	   delay until the thread is canceled.  And we will unlikely +	   enter the loop twice.  */ +4:	movq	%fs:0, %rdi +	movl	$__NR_futex, %eax +	xorq	%r10, %r10 +	addq	$CANCELHANDLING, %rdi +	LOAD_PRIVATE_FUTEX_WAIT (%esi) +	syscall +	movl	%fs:CANCELHANDLING, %eax +	jmp	3b +END(__pthread_disable_asynccancel) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/clone.S new file mode 100644 index 000000000..efbaee3d1 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/clone.S @@ -0,0 +1,3 @@ +#include <tcb-offsets.h> +#define RESET_PID +#include <libc/sysdeps/linux/x86_64/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/compat-timer.h b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/compat-timer.h new file mode 100644 index 000000000..02485daa5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/compat-timer.h @@ -0,0 +1,46 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; see the file COPYING.LIB.  If not, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +#include <signal.h> +#include <time.h> +#include <sys/types.h> + +#define OLD_TIMER_MAX	256 + +extern timer_t __compat_timer_list[OLD_TIMER_MAX] attribute_hidden; + + +extern int __timer_create_new (clockid_t clock_id, struct sigevent *evp, +			       timer_t *timerid); +extern int __timer_delete_new (timer_t timerid); +extern int __timer_getoverrun_new (timer_t timerid); +extern int __timer_gettime_new (timer_t timerid, struct itimerspec *value); +extern int __timer_settime_new (timer_t timerid, int flags, +				const struct itimerspec *value, +				struct itimerspec *ovalue); + + +extern int __timer_create_old (clockid_t clock_id, struct sigevent *evp, +			       int *timerid); +extern int __timer_delete_old (int timerid); +extern int __timer_getoverrun_old (int timerid); +extern int __timer_gettime_old (int timerid, struct itimerspec *value); +extern int __timer_settime_old (int timerid, int flags, +				const struct itimerspec *value, +				struct itimerspec *ovalue); diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/fork.c new file mode 100644 index 000000000..c828e158d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/fork.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sched.h> +#include <signal.h> +#include <sysdep.h> +#include <tls.h> + + +#define ARCH_FORK() \ +  INLINE_SYSCALL (clone, 4,						      \ +		  CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0,     \ +		  NULL, &THREAD_SELF->tid) + +#include "../fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/libc-cancellation.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/libc-cancellation.S new file mode 100644 index 000000000..110058850 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/libc-cancellation.S @@ -0,0 +1,22 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2009. + +   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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#define __pthread_enable_asynccancel __libc_enable_asynccancel +#define __pthread_disable_asynccancel __libc_disable_asynccancel +#include "cancellation.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/libc-lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/libc-lowlevellock.S new file mode 100644 index 000000000..ce8ad27aa --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/libc-lowlevellock.S @@ -0,0 +1,20 @@ +/* Copyright (C) 2002, 2003, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "lowlevellock.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/librt-cancellation.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/librt-cancellation.S new file mode 100644 index 000000000..ce4192b5d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/librt-cancellation.S @@ -0,0 +1,22 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2009. + +   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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#define __pthread_enable_asynccancel __librt_enable_asynccancel +#define __pthread_disable_asynccancel __librt_disable_asynccancel +#include "cancellation.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S new file mode 100644 index 000000000..f87532359 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S @@ -0,0 +1,457 @@ +/* Copyright (C) 2002-2006, 2007, 2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <bits/kernel-features.h> +#include <lowlevellock.h> +#include <tcb-offsets.h> + +	.text + +#ifdef __ASSUME_PRIVATE_FUTEX +# define LOAD_PRIVATE_FUTEX_WAIT(reg) \ +	movl	$(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg +# define LOAD_PRIVATE_FUTEX_WAKE(reg) \ +	movl	$(FUTEX_WAKE | FUTEX_PRIVATE_FLAG), reg +# define LOAD_FUTEX_WAIT(reg) \ +	xorl	$(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg +# define LOAD_FUTEX_WAIT_ABS(reg) \ +	xorl	$(FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME), reg +# define LOAD_FUTEX_WAKE(reg) \ +	xorl	$(FUTEX_WAKE | FUTEX_PRIVATE_FLAG), reg +#else +# if FUTEX_WAIT == 0 +#  define LOAD_PRIVATE_FUTEX_WAIT(reg) \ +	movl    %fs:PRIVATE_FUTEX, reg +# else +#  define LOAD_PRIVATE_FUTEX_WAIT(reg) \ +	movl	%fs:PRIVATE_FUTEX, reg ; \ +	orl	$FUTEX_WAIT, reg +# endif +# define LOAD_PRIVATE_FUTEX_WAKE(reg) \ +	movl    %fs:PRIVATE_FUTEX, reg ; \ +	orl     $FUTEX_WAKE, reg +# if FUTEX_WAIT == 0 +#  define LOAD_FUTEX_WAIT(reg) \ +	xorl	$FUTEX_PRIVATE_FLAG, reg ; \ +	andl	%fs:PRIVATE_FUTEX, reg +# else +#  define LOAD_FUTEX_WAIT(reg) \ +	xorl	$FUTEX_PRIVATE_FLAG, reg ; \ +	andl	%fs:PRIVATE_FUTEX, reg ; \ +	orl	$FUTEX_WAIT, reg +# endif +# define LOAD_FUTEX_WAIT_ABS(reg) \ +	xorl	$FUTEX_PRIVATE_FLAG, reg ; \ +	andl	%fs:PRIVATE_FUTEX, reg ; \ +	orl	$FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME, reg +# define LOAD_FUTEX_WAKE(reg) \ +	xorl	$FUTEX_PRIVATE_FLAG, reg ; \ +	andl	%fs:PRIVATE_FUTEX, reg ; \ +	orl	$FUTEX_WAKE, reg +#endif + + +/* For the calculation see asm/vsyscall.h.  */ +#define VSYSCALL_ADDR_vgettimeofday	0xffffffffff600000 + + +	.globl	__lll_lock_wait_private +	.type	__lll_lock_wait_private,@function +	.hidden	__lll_lock_wait_private +	.align	16 +__lll_lock_wait_private: +	cfi_startproc +	pushq	%r10 +	cfi_adjust_cfa_offset(8) +	pushq	%rdx +	cfi_adjust_cfa_offset(8) +	cfi_offset(%r10, -16) +	cfi_offset(%rdx, -24) +	xorq	%r10, %r10	/* No timeout.  */ +	movl	$2, %edx +	LOAD_PRIVATE_FUTEX_WAIT (%esi) + +	cmpl	%edx, %eax	/* NB:	 %edx == 2 */ +	jne	2f + +1:	movl	$SYS_futex, %eax +	syscall + +2:	movl	%edx, %eax +	xchgl	%eax, (%rdi)	/* NB:	 lock is implied */ + +	testl	%eax, %eax +	jnz	1b + +	popq	%rdx +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%rdx) +	popq	%r10 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r10) +	retq +	cfi_endproc +	.size	__lll_lock_wait_private,.-__lll_lock_wait_private + +#ifdef NOT_IN_libc +	.globl	__lll_lock_wait +	.type	__lll_lock_wait,@function +	.hidden	__lll_lock_wait +	.align	16 +__lll_lock_wait: +	cfi_startproc +	pushq	%r10 +	cfi_adjust_cfa_offset(8) +	pushq	%rdx +	cfi_adjust_cfa_offset(8) +	cfi_offset(%r10, -16) +	cfi_offset(%rdx, -24) +	xorq	%r10, %r10	/* No timeout.  */ +	movl	$2, %edx +	LOAD_FUTEX_WAIT (%esi) + +	cmpl	%edx, %eax	/* NB:	 %edx == 2 */ +	jne	2f + +1:	movl	$SYS_futex, %eax +	syscall + +2:	movl	%edx, %eax +	xchgl	%eax, (%rdi)	/* NB:	 lock is implied */ + +	testl	%eax, %eax +	jnz	1b + +	popq	%rdx +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%rdx) +	popq	%r10 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r10) +	retq +	cfi_endproc +	.size	__lll_lock_wait,.-__lll_lock_wait + +	/*      %rdi: futex +		%rsi: flags +		%rdx: timeout +		%eax: futex value +	*/ +	.globl	__lll_timedlock_wait +	.type	__lll_timedlock_wait,@function +	.hidden	__lll_timedlock_wait +	.align	16 +__lll_timedlock_wait: +	cfi_startproc +# ifndef __ASSUME_FUTEX_CLOCK_REALTIME +#  ifdef __PIC__ +	cmpl	$0, __have_futex_clock_realtime(%rip) +#  else +	cmpl	$0, __have_futex_clock_realtime +#  endif +	je	.Lreltmo +# endif + +	pushq	%r9 +	cfi_adjust_cfa_offset(8) +	cfi_rel_offset(%r9, 0) +	movq	%rdx, %r10 +	movl	$0xffffffff, %r9d +	LOAD_FUTEX_WAIT_ABS (%esi) + +	movl	$2, %edx +	cmpl	%edx, %eax +	jne	2f + +1:	movl	$SYS_futex, %eax +	movl	$2, %edx +	syscall + +2:	xchgl	%edx, (%rdi)	/* NB:   lock is implied */ + +	testl	%edx, %edx +	jz	3f + +	cmpl	$-ETIMEDOUT, %eax +	je	4f +	cmpl	$-EINVAL, %eax +	jne	1b +4:	movl	%eax, %edx +	negl	%edx + +3:	movl	%edx, %eax +	popq	%r9 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r9) +	retq + +# ifndef __ASSUME_FUTEX_CLOCK_REALTIME +.Lreltmo: +	/* Check for a valid timeout value.  */ +	cmpq	$1000000000, 8(%rdx) +	jae	3f + +	pushq	%r8 +	cfi_adjust_cfa_offset(8) +	pushq	%r9 +	cfi_adjust_cfa_offset(8) +	pushq	%r12 +	cfi_adjust_cfa_offset(8) +	pushq	%r13 +	cfi_adjust_cfa_offset(8) +	pushq	%r14 +	cfi_adjust_cfa_offset(8) +	cfi_offset(%r8, -16) +	cfi_offset(%r9, -24) +	cfi_offset(%r12, -32) +	cfi_offset(%r13, -40) +	cfi_offset(%r14, -48) +	pushq	%rsi +	cfi_adjust_cfa_offset(8) + +	/* Stack frame for the timespec and timeval structs.  */ +	subq	$24, %rsp +	cfi_adjust_cfa_offset(24) + +	movq	%rdi, %r12 +	movq	%rdx, %r13 + +	movl	$2, %edx +	xchgl	%edx, (%r12) + +	testl	%edx, %edx +	je	6f + +1: +	/* Get current time.  */ +	movq	%rsp, %rdi +	xorl	%esi, %esi +	movq	$VSYSCALL_ADDR_vgettimeofday, %rax +	/* This is a regular function call, all caller-save registers +	   might be clobbered.  */ +	callq	*%rax + +	/* Compute relative timeout.  */ +	movq	8(%rsp), %rax +	movl	$1000, %edi +	mul	%rdi		/* Milli seconds to nano seconds.  */ +	movq	(%r13), %rdi +	movq	8(%r13), %rsi +	subq	(%rsp), %rdi +	subq	%rax, %rsi +	jns	4f +	addq	$1000000000, %rsi +	decq	%rdi +4:	testq	%rdi, %rdi +	js	2f		/* Time is already up.  */ + +	/* Store relative timeout.  */ +	movq	%rdi, (%rsp) +	movq	%rsi, 8(%rsp) + +	/* Futex call.  */ +	movl	$2, %edx +	movl	$1, %eax +	movq	%rsp, %r10 +	movl	24(%rsp), %esi +	LOAD_FUTEX_WAIT (%esi) +	movq	%r12, %rdi +	movl	$SYS_futex, %eax +	syscall + +	/* NB: %edx == 2 */ +	xchgl	%edx, (%r12) + +	testl	%edx, %edx +	je	6f + +	cmpl	$-ETIMEDOUT, %eax +	jne	1b +2:	movl	$ETIMEDOUT, %edx + +6:	addq	$32, %rsp +	cfi_adjust_cfa_offset(-32) +	popq	%r14 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r14) +	popq	%r13 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r13) +	popq	%r12 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r12) +	popq	%r9 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r9) +	popq	%r8 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r8) +	movl	%edx, %eax +	retq + +3:	movl	$EINVAL, %eax +	retq +# endif +	cfi_endproc +	.size	__lll_timedlock_wait,.-__lll_timedlock_wait +#endif + + +	.globl	__lll_unlock_wake_private +	.type	__lll_unlock_wake_private,@function +	.hidden	__lll_unlock_wake_private +	.align	16 +__lll_unlock_wake_private: +	cfi_startproc +	pushq	%rsi +	cfi_adjust_cfa_offset(8) +	pushq	%rdx +	cfi_adjust_cfa_offset(8) +	cfi_offset(%rsi, -16) +	cfi_offset(%rdx, -24) + +	movl	$0, (%rdi) +	LOAD_PRIVATE_FUTEX_WAKE (%esi) +	movl	$1, %edx	/* Wake one thread.  */ +	movl	$SYS_futex, %eax +	syscall + +	popq	%rdx +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%rdx) +	popq	%rsi +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%rsi) +	retq +	cfi_endproc +	.size	__lll_unlock_wake_private,.-__lll_unlock_wake_private + +#ifdef NOT_IN_libc +	.globl	__lll_unlock_wake +	.type	__lll_unlock_wake,@function +	.hidden	__lll_unlock_wake +	.align	16 +__lll_unlock_wake: +	cfi_startproc +	pushq	%rsi +	cfi_adjust_cfa_offset(8) +	pushq	%rdx +	cfi_adjust_cfa_offset(8) +	cfi_offset(%rsi, -16) +	cfi_offset(%rdx, -24) + +	movl	$0, (%rdi) +	LOAD_FUTEX_WAKE (%esi) +	movl	$1, %edx	/* Wake one thread.  */ +	movl	$SYS_futex, %eax +	syscall + +	popq	%rdx +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%rdx) +	popq	%rsi +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%rsi) +	retq +	cfi_endproc +	.size	__lll_unlock_wake,.-__lll_unlock_wake + +	.globl	__lll_timedwait_tid +	.type	__lll_timedwait_tid,@function +	.hidden	__lll_timedwait_tid +	.align	16 +__lll_timedwait_tid: +	cfi_startproc +	pushq	%r12 +	cfi_adjust_cfa_offset(8) +	pushq	%r13 +	cfi_adjust_cfa_offset(8) +	cfi_offset(%r12, -16) +	cfi_offset(%r13, -24) + +	movq	%rdi, %r12 +	movq	%rsi, %r13 + +	subq	$16, %rsp +	cfi_adjust_cfa_offset(16) + +	/* Get current time.  */ +2:	movq	%rsp, %rdi +	xorl	%esi, %esi +	movq	$VSYSCALL_ADDR_vgettimeofday, %rax +	callq	*%rax + +	/* Compute relative timeout.  */ +	movq	8(%rsp), %rax +	movl	$1000, %edi +	mul	%rdi		/* Milli seconds to nano seconds.  */ +	movq	(%r13), %rdi +	movq	8(%r13), %rsi +	subq	(%rsp), %rdi +	subq	%rax, %rsi +	jns	5f +	addq	$1000000000, %rsi +	decq	%rdi +5:	testq	%rdi, %rdi +	js	6f		/* Time is already up.  */ + +	movq	%rdi, (%rsp)	/* Store relative timeout.  */ +	movq	%rsi, 8(%rsp) + +	movl	(%r12), %edx +	testl	%edx, %edx +	jz	4f + +	movq	%rsp, %r10 +	/* XXX The kernel so far uses global futex for the wakeup at +	   all times.  */ +#if FUTEX_WAIT == 0 +	xorl	%esi, %esi +#else +	movl	$FUTEX_WAIT, %esi +#endif +	movq	%r12, %rdi +	movl	$SYS_futex, %eax +	syscall + +	cmpl	$0, (%rdi) +	jne	1f +4:	xorl	%eax, %eax + +8:	addq	$16, %rsp +	cfi_adjust_cfa_offset(-16) +	popq	%r13 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r13) +	popq	%r12 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r12) +	retq + +	cfi_adjust_cfa_offset(32) +1:	cmpq	$-ETIMEDOUT, %rax +	jne	2b + +6:	movl	$ETIMEDOUT, %eax +	jmp	8b +	cfi_endproc +	.size	__lll_timedwait_tid,.-__lll_timedwait_tid +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h new file mode 100644 index 000000000..7c042fc80 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h @@ -0,0 +1,598 @@ +/* Copyright (C) 2002-2004, 2006-2008, 2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H	1 + +#ifndef __ASSEMBLER__ +# include <time.h> +# include <sys/param.h> +# include <bits/pthreadtypes.h> +# include <bits/kernel-features.h> +# include <tcb-offsets.h> + +# ifndef LOCK_INSTR +#  ifdef UP +#   define LOCK_INSTR	/* nothing */ +#  else +#   define LOCK_INSTR "lock;" +#  endif +# endif +#else +# ifndef LOCK +#  ifdef UP +#   define LOCK +#  else +#   define LOCK lock +#  endif +# endif +#endif + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 +#define FUTEX_CMP_REQUEUE	4 +#define FUTEX_WAKE_OP		5 +#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 + +#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE	((4 << 24) | 1) + +/* Values for 'private' parameter of locking macros.  Yes, the +   definition seems to be backwards.  But it is not.  The bit will be +   reversed before passing to the system call.  */ +#define LLL_PRIVATE	0 +#define LLL_SHARED	FUTEX_PRIVATE_FLAG + +#ifndef __ASSEMBLER__ + +#if !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))								      \ +   : ({ unsigned int __fl = ((private) ^ FUTEX_PRIVATE_FLAG);		      \ +	__asm__ ("andl %%fs:%P1, %0" : "+r" (__fl)				      \ +	     : "i" (offsetof (struct pthread, header.private_futex)));	      \ +	__fl | (fl); })) +# endif +#endif + +/* Initializer for lock.  */ +#define LLL_LOCK_INITIALIZER		(0) +#define LLL_LOCK_INITIALIZER_LOCKED	(1) +#define LLL_LOCK_INITIALIZER_WAITERS	(2) + +/* Delay in spinlock loop.  */ +#define BUSY_WAIT_NOP	  __asm__ ("rep; nop") + + +#define LLL_STUB_UNWIND_INFO_START \ +	".section	.eh_frame,\"a\",@progbits\n" 		\ +"7:\t"	".long	9f-8f	# Length of Common Information Entry\n" \ +"8:\t"	".long	0x0	# CIE Identifier Tag\n\t" 		\ +	".byte	0x1	# CIE Version\n\t" 			\ +	".ascii \"zR\\0\"	# CIE Augmentation\n\t" 	\ +	".uleb128 0x1	# CIE Code Alignment Factor\n\t" 	\ +	".sleb128 -8	# CIE Data Alignment Factor\n\t" 	\ +	".byte	0x10	# CIE RA Column\n\t" 			\ +	".uleb128 0x1	# Augmentation size\n\t" 		\ +	".byte	0x1b	# FDE Encoding (pcrel sdata4)\n\t" 	\ +	".byte	0x12	# DW_CFA_def_cfa_sf\n\t" 		\ +	".uleb128 0x7\n\t" 					\ +	".sleb128 16\n\t" 					\ +	".align 8\n" 						\ +"9:\t"	".long	23f-10f	# FDE Length\n" 			\ +"10:\t"	".long	10b-7b	# FDE CIE offset\n\t" 			\ +	".long	1b-.	# FDE initial location\n\t" 		\ +	".long	6b-1b	# FDE address range\n\t" 		\ +	".uleb128 0x0	# Augmentation size\n\t" 		\ +	".byte	0x16	# DW_CFA_val_expression\n\t" 		\ +	".uleb128 0x10\n\t" 					\ +	".uleb128 12f-11f\n" 					\ +"11:\t"	".byte	0x80	# DW_OP_breg16\n\t" 			\ +	".sleb128 4b-1b\n" +#define LLL_STUB_UNWIND_INFO_END \ +	".byte	0x16	# DW_CFA_val_expression\n\t" 		\ +	".uleb128 0x10\n\t" 					\ +	".uleb128 14f-13f\n" 					\ +"13:\t"	".byte	0x80	# DW_OP_breg16\n\t" 			\ +	".sleb128 4b-2b\n" 					\ +"14:\t"	".byte	0x40 + (3b-2b) # DW_CFA_advance_loc\n\t" 	\ +	".byte	0x0e	# DW_CFA_def_cfa_offset\n\t" 		\ +	".uleb128 0\n\t" 					\ +	".byte	0x16	# DW_CFA_val_expression\n\t" 		\ +	".uleb128 0x10\n\t" 					\ +	".uleb128 16f-15f\n" 					\ +"15:\t"	".byte	0x80	# DW_OP_breg16\n\t" 			\ +	".sleb128 4b-3b\n" 					\ +"16:\t"	".byte	0x40 + (4b-3b-1) # DW_CFA_advance_loc\n\t" 	\ +	".byte	0x0e	# DW_CFA_def_cfa_offset\n\t" 		\ +	".uleb128 128\n\t" 					\ +	".byte	0x16	# DW_CFA_val_expression\n\t" 		\ +	".uleb128 0x10\n\t" 					\ +	".uleb128 20f-17f\n" 					\ +"17:\t"	".byte	0x80	# DW_OP_breg16\n\t" 			\ +	".sleb128 19f-18f\n\t" 					\ +	".byte	0x0d	# DW_OP_const4s\n" 			\ +"18:\t"	".4byte	4b-.\n\t" 					\ +	".byte	0x1c	# DW_OP_minus\n\t" 			\ +	".byte	0x0d	# DW_OP_const4s\n" 			\ +"19:\t"	".4byte	24f-.\n\t" 					\ +	".byte	0x22	# DW_OP_plus\n" 			\ +"20:\t"	".byte	0x40 + (5b-4b+1) # DW_CFA_advance_loc\n\t" 	\ +	".byte	0x13	# DW_CFA_def_cfa_offset_sf\n\t" 	\ +	".sleb128 16\n\t" 					\ +	".byte	0x16	# DW_CFA_val_expression\n\t" 		\ +	".uleb128 0x10\n\t" 					\ +	".uleb128 22f-21f\n" 					\ +"21:\t"	".byte	0x80	# DW_OP_breg16\n\t" 			\ +	".sleb128 4b-5b\n" 					\ +"22:\t"	".align 8\n" 						\ +"23:\t"	".previous\n" + +/* Unwind info for +   1: leaq ..., %rdi +   2: subq $128, %rsp +   3: callq ... +   4: addq $128, %rsp +   5: jmp 24f +   6: +   snippet.  */ +#define LLL_STUB_UNWIND_INFO_5 \ +LLL_STUB_UNWIND_INFO_START					\ +"12:\t"	".byte	0x40 + (2b-1b) # DW_CFA_advance_loc\n\t" 	\ +LLL_STUB_UNWIND_INFO_END + +/* Unwind info for +   1: leaq ..., %rdi +   0: movq ..., %rdx +   2: subq $128, %rsp +   3: callq ... +   4: addq $128, %rsp +   5: jmp 24f +   6: +   snippet.  */ +#define LLL_STUB_UNWIND_INFO_6 \ +LLL_STUB_UNWIND_INFO_START					\ +"12:\t"	".byte	0x40 + (0b-1b) # DW_CFA_advance_loc\n\t" 	\ +	".byte	0x16	# DW_CFA_val_expression\n\t" 		\ +	".uleb128 0x10\n\t" 					\ +	".uleb128 26f-25f\n" 					\ +"25:\t"	".byte	0x80	# DW_OP_breg16\n\t" 			\ +	".sleb128 4b-0b\n" 					\ +"26:\t"	".byte	0x40 + (2b-0b) # DW_CFA_advance_loc\n\t" 	\ +LLL_STUB_UNWIND_INFO_END + + +#define lll_futex_wait(futex, val, private) \ +  lll_futex_timed_wait(futex, val, NULL, private) + + +#define lll_futex_timed_wait(futex, val, timeout, private) \ +  ({									      \ +    register const struct timespec *__to __asm__ ("r10") = timeout;	      \ +    int __status;							      \ +    register __typeof (val) _val __asm__ ("edx") = (val);			      \ +    __asm__ __volatile ("syscall"						      \ +		      : "=a" (__status)					      \ +		      : "0" (SYS_futex), "D" (futex),			      \ +			"S" (__lll_private_flag (FUTEX_WAIT, private)),	      \ +			"d" (_val), "r" (__to)				      \ +		      : "memory", "cc", "r11", "cx");			      \ +    __status;								      \ +  }) + + +#define lll_futex_wake(futex, nr, private) \ +  do {									      \ +    int __ignore;							      \ +    register __typeof (nr) _nr __asm__ ("edx") = (nr);			      \ +    __asm__ __volatile ("syscall"						      \ +		      : "=a" (__ignore)					      \ +		      : "0" (SYS_futex), "D" (futex),			      \ +			"S" (__lll_private_flag (FUTEX_WAKE, private)),	      \ +			"d" (_nr)					      \ +		      : "memory", "cc", "r10", "r11", "cx");		      \ +  } while (0) + + +/* NB: in the lll_trylock macro we simply return the value in %eax +   after the cmpxchg instruction.  In case the operation succeded this +   value is zero.  In case the operation failed, the cmpxchg instruction +   has loaded the current value of the memory work which is guaranteed +   to be nonzero.  */ +#if defined NOT_IN_libc || defined UP +# define __lll_trylock_asm LOCK_INSTR "cmpxchgl %2, %1" +#else +# define __lll_trylock_asm "cmpl $0, __libc_multiple_threads(%%rip)\n\t"      \ +			   "je 0f\n\t"					      \ +			   "lock; cmpxchgl %2, %1\n\t"			      \ +			   "jmp 1f\n\t"					      \ +			   "0:\tcmpxchgl %2, %1\n\t"			      \ +			   "1:" +#endif + +#define lll_trylock(futex) \ +  ({ int ret;								      \ +     __asm__ __volatile (__lll_trylock_asm				      \ +		       : "=a" (ret), "=m" (futex)			      \ +		       : "r" (LLL_LOCK_INITIALIZER_LOCKED), "m" (futex),      \ +			 "0" (LLL_LOCK_INITIALIZER)			      \ +		       : "memory");					      \ +     ret; }) + +#define lll_robust_trylock(futex, id) \ +  ({ int ret;								      \ +     __asm__ __volatile (LOCK_INSTR "cmpxchgl %2, %1"			      \ +		       : "=a" (ret), "=m" (futex)			      \ +		       : "r" (id), "m" (futex),	"0" (LLL_LOCK_INITIALIZER)    \ +		       : "memory");					      \ +     ret; }) + +#define lll_cond_trylock(futex) \ +  ({ int ret;								      \ +     __asm__ __volatile (LOCK_INSTR "cmpxchgl %2, %1"			      \ +		       : "=a" (ret), "=m" (futex)			      \ +		       : "r" (LLL_LOCK_INITIALIZER_WAITERS),		      \ +			 "m" (futex), "0" (LLL_LOCK_INITIALIZER)	      \ +		       : "memory");					      \ +     ret; }) + +#if defined NOT_IN_libc || defined UP +# define __lll_lock_asm_start LOCK_INSTR "cmpxchgl %4, %2\n\t"		      \ +			      "jnz 1f\n\t" +#else +# define __lll_lock_asm_start "cmpl $0, __libc_multiple_threads(%%rip)\n\t"   \ +			      "je 0f\n\t"				      \ +			      "lock; cmpxchgl %4, %2\n\t"		      \ +			      "jnz 1f\n\t"				      \ +		  	      "jmp 24f\n"				      \ +			      "0:\tcmpxchgl %4, %2\n\t"			      \ +			      "jnz 1f\n\t" +#endif + +#define lll_lock(futex, private) \ +  (void)								      \ +    ({ int ignore1, ignore2, ignore3;					      \ +       if (__builtin_constant_p (private) && (private) == LLL_PRIVATE)	      \ +	 __asm__ __volatile (__lll_lock_asm_start				      \ +			   ".subsection 1\n\t"				      \ +			   ".type _L_lock_%=, @function\n"		      \ +			   "_L_lock_%=:\n"				      \ +			   "1:\tleaq %2, %%rdi\n"			      \ +			   "2:\tsubq $128, %%rsp\n"			      \ +			   "3:\tcallq __lll_lock_wait_private\n"	      \ +			   "4:\taddq $128, %%rsp\n"			      \ +			   "5:\tjmp 24f\n"				      \ +			   "6:\t.size _L_lock_%=, 6b-1b\n\t"		      \ +			   ".previous\n"				      \ +			   LLL_STUB_UNWIND_INFO_5			      \ +			   "24:"					      \ +			   : "=S" (ignore1), "=&D" (ignore2), "=m" (futex),   \ +			     "=a" (ignore3)				      \ +			   : "0" (1), "m" (futex), "3" (0)		      \ +			   : "cx", "r11", "cc", "memory");		      \ +       else								      \ +	 __asm__ __volatile (__lll_lock_asm_start				      \ +			   ".subsection 1\n\t"				      \ +			   ".type _L_lock_%=, @function\n"		      \ +			   "_L_lock_%=:\n"				      \ +			   "1:\tleaq %2, %%rdi\n"			      \ +			   "2:\tsubq $128, %%rsp\n"			      \ +			   "3:\tcallq __lll_lock_wait\n"		      \ +			   "4:\taddq $128, %%rsp\n"			      \ +			   "5:\tjmp 24f\n"				      \ +			   "6:\t.size _L_lock_%=, 6b-1b\n\t"		      \ +			   ".previous\n"				      \ +			   LLL_STUB_UNWIND_INFO_5			      \ +			   "24:"					      \ +			   : "=S" (ignore1), "=D" (ignore2), "=m" (futex),    \ +			     "=a" (ignore3)				      \ +			   : "1" (1), "m" (futex), "3" (0), "0" (private)     \ +			   : "cx", "r11", "cc", "memory");		      \ +    })									      \ + +#define lll_robust_lock(futex, id, private) \ +  ({ int result, ignore1, ignore2;					      \ +    __asm__ __volatile (LOCK_INSTR "cmpxchgl %4, %2\n\t"			      \ +		      "jnz 1f\n\t"					      \ +		      ".subsection 1\n\t"				      \ +		      ".type _L_robust_lock_%=, @function\n"		      \ +		      "_L_robust_lock_%=:\n"				      \ +		      "1:\tleaq %2, %%rdi\n"				      \ +		      "2:\tsubq $128, %%rsp\n"				      \ +		      "3:\tcallq __lll_robust_lock_wait\n"		      \ +		      "4:\taddq $128, %%rsp\n"				      \ +		      "5:\tjmp 24f\n"					      \ +		      "6:\t.size _L_robust_lock_%=, 6b-1b\n\t"		      \ +		      ".previous\n"					      \ +		      LLL_STUB_UNWIND_INFO_5				      \ +		      "24:"						      \ +		      : "=S" (ignore1), "=D" (ignore2), "=m" (futex),	      \ +			"=a" (result)					      \ +		      : "1" (id), "m" (futex), "3" (0), "0" (private)	      \ +		      : "cx", "r11", "cc", "memory");			      \ +    result; }) + +#define lll_cond_lock(futex, private) \ +  (void)								      \ +    ({ int ignore1, ignore2, ignore3;					      \ +       __asm__ __volatile (LOCK_INSTR "cmpxchgl %4, %2\n\t"		      \ +			 "jnz 1f\n\t"					      \ +			 ".subsection 1\n\t"				      \ +			 ".type _L_cond_lock_%=, @function\n"		      \ +			 "_L_cond_lock_%=:\n"				      \ +			 "1:\tleaq %2, %%rdi\n"				      \ +			 "2:\tsubq $128, %%rsp\n"			      \ +			 "3:\tcallq __lll_lock_wait\n"			      \ +			 "4:\taddq $128, %%rsp\n"			      \ +			 "5:\tjmp 24f\n"				      \ +			 "6:\t.size _L_cond_lock_%=, 6b-1b\n\t"		      \ +			 ".previous\n"					      \ +			 LLL_STUB_UNWIND_INFO_5				      \ +			 "24:"						      \ +			 : "=S" (ignore1), "=D" (ignore2), "=m" (futex),      \ +			   "=a" (ignore3)				      \ +			 : "1" (2), "m" (futex), "3" (0), "0" (private)	      \ +			 : "cx", "r11", "cc", "memory");		      \ +    }) + +#define lll_robust_cond_lock(futex, id, private) \ +  ({ int result, ignore1, ignore2;					      \ +    __asm__ __volatile (LOCK_INSTR "cmpxchgl %4, %2\n\t"			      \ +		      "jnz 1f\n\t"					      \ +		      ".subsection 1\n\t"				      \ +		      ".type _L_robust_cond_lock_%=, @function\n"	      \ +		      "_L_robust_cond_lock_%=:\n"			      \ +		      "1:\tleaq %2, %%rdi\n"				      \ +		      "2:\tsubq $128, %%rsp\n"				      \ +		      "3:\tcallq __lll_robust_lock_wait\n"		      \ +		      "4:\taddq $128, %%rsp\n"				      \ +		      "5:\tjmp 24f\n"					      \ +		      "6:\t.size _L_robust_cond_lock_%=, 6b-1b\n\t"	      \ +		      ".previous\n"					      \ +		      LLL_STUB_UNWIND_INFO_5				      \ +		      "24:"						      \ +		      : "=S" (ignore1), "=D" (ignore2), "=m" (futex),	      \ +			"=a" (result)					      \ +		      : "1" (id | FUTEX_WAITERS), "m" (futex), "3" (0),	      \ +			"0" (private)					      \ +		      : "cx", "r11", "cc", "memory");			      \ +    result; }) + +#define lll_timedlock(futex, timeout, private) \ +  ({ int result, ignore1, ignore2, ignore3;				      \ +     __asm__ __volatile (LOCK_INSTR "cmpxchgl %1, %4\n\t"			      \ +		       "jnz 1f\n\t"					      \ +		       ".subsection 1\n\t"				      \ +		       ".type _L_timedlock_%=, @function\n"		      \ +		       "_L_timedlock_%=:\n"				      \ +		       "1:\tleaq %4, %%rdi\n"				      \ +		       "0:\tmovq %8, %%rdx\n"				      \ +		       "2:\tsubq $128, %%rsp\n"				      \ +		       "3:\tcallq __lll_timedlock_wait\n"		      \ +		       "4:\taddq $128, %%rsp\n"				      \ +		       "5:\tjmp 24f\n"					      \ +		       "6:\t.size _L_timedlock_%=, 6b-1b\n\t"		      \ +		       ".previous\n"					      \ +		       LLL_STUB_UNWIND_INFO_6				      \ +		       "24:"						      \ +		       : "=a" (result), "=D" (ignore1), "=S" (ignore2),	      \ +			 "=&d" (ignore3), "=m" (futex)			      \ +		       : "0" (0), "1" (1), "m" (futex), "m" (timeout),	      \ +			 "2" (private)					      \ +		       : "memory", "cx", "cc", "r10", "r11");		      \ +     result; }) + +#define lll_robust_timedlock(futex, timeout, id, private) \ +  ({ int result, ignore1, ignore2, ignore3;				      \ +     __asm__ __volatile (LOCK_INSTR "cmpxchgl %1, %4\n\t"			      \ +		       "jnz 1f\n\t"					      \ +		       ".subsection 1\n\t"				      \ +		       ".type _L_robust_timedlock_%=, @function\n"	      \ +		       "_L_robust_timedlock_%=:\n"			      \ +		       "1:\tleaq %4, %%rdi\n"				      \ +		       "0:\tmovq %8, %%rdx\n"				      \ +		       "2:\tsubq $128, %%rsp\n"				      \ +		       "3:\tcallq __lll_robust_timedlock_wait\n"	      \ +		       "4:\taddq $128, %%rsp\n"				      \ +		       "5:\tjmp 24f\n"					      \ +		       "6:\t.size _L_robust_timedlock_%=, 6b-1b\n\t"	      \ +		       ".previous\n"					      \ +		       LLL_STUB_UNWIND_INFO_6				      \ +		       "24:"						      \ +		       : "=a" (result), "=D" (ignore1), "=S" (ignore2),       \ +			 "=&d" (ignore3), "=m" (futex)			      \ +		       : "0" (0), "1" (id), "m" (futex), "m" (timeout),	      \ +			 "2" (private)					      \ +		       : "memory", "cx", "cc", "r10", "r11");		      \ +     result; }) + +#if defined NOT_IN_libc || defined UP +# define __lll_unlock_asm_start LOCK_INSTR "decl %0\n\t"		      \ +				"jne 1f\n\t" +#else +# define __lll_unlock_asm_start "cmpl $0, __libc_multiple_threads(%%rip)\n\t" \ +				"je 0f\n\t"				      \ +				"lock; decl %0\n\t"			      \ +				"jne 1f\n\t"				      \ +				"jmp 24f\n\t"				      \ +				"0:\tdecl %0\n\t"			      \ +				"jne 1f\n\t" +#endif + +#define lll_unlock(futex, private) \ +  (void)								      \ +    ({ int ignore;							      \ +       if (__builtin_constant_p (private) && (private) == LLL_PRIVATE)	      \ +	 __asm__ __volatile (__lll_unlock_asm_start			      \ +			   ".subsection 1\n\t"				      \ +			   ".type _L_unlock_%=, @function\n"		      \ +			   "_L_unlock_%=:\n"				      \ +			   "1:\tleaq %0, %%rdi\n"			      \ +			   "2:\tsubq $128, %%rsp\n"			      \ +			   "3:\tcallq __lll_unlock_wake_private\n"	      \ +			   "4:\taddq $128, %%rsp\n"			      \ +			   "5:\tjmp 24f\n"				      \ +			   "6:\t.size _L_unlock_%=, 6b-1b\n\t"		      \ +			   ".previous\n"				      \ +			   LLL_STUB_UNWIND_INFO_5			      \ +			   "24:"					      \ +			   : "=m" (futex), "=&D" (ignore)		      \ +			   : "m" (futex)				      \ +			   : "ax", "cx", "r11", "cc", "memory");	      \ +       else								      \ +	 __asm__ __volatile (__lll_unlock_asm_start			      \ +			   ".subsection 1\n\t"				      \ +			   ".type _L_unlock_%=, @function\n"		      \ +			   "_L_unlock_%=:\n"				      \ +			   "1:\tleaq %0, %%rdi\n"			      \ +			   "2:\tsubq $128, %%rsp\n"			      \ +			   "3:\tcallq __lll_unlock_wake\n"		      \ +			   "4:\taddq $128, %%rsp\n"			      \ +			   "5:\tjmp 24f\n"				      \ +			   "6:\t.size _L_unlock_%=, 6b-1b\n\t"		      \ +			   ".previous\n"				      \ +			   LLL_STUB_UNWIND_INFO_5			      \ +			   "24:"					      \ +			   : "=m" (futex), "=&D" (ignore)		      \ +			   : "m" (futex), "S" (private)			      \ +			   : "ax", "cx", "r11", "cc", "memory");	      \ +    }) + +#define lll_robust_unlock(futex, private) \ +  do									      \ +    {									      \ +      int ignore;							      \ +      __asm__ __volatile (LOCK_INSTR "andl %2, %0\n\t"			      \ +			"jne 1f\n\t"					      \ +			".subsection 1\n\t"				      \ +			".type _L_robust_unlock_%=, @function\n"	      \ +			"_L_robust_unlock_%=:\n"			      \ +			"1:\tleaq %0, %%rdi\n"				      \ +			"2:\tsubq $128, %%rsp\n"			      \ +			"3:\tcallq __lll_unlock_wake\n"			      \ +			"4:\taddq $128, %%rsp\n"			      \ +			"5:\tjmp 24f\n"					      \ +			"6:\t.size _L_robust_unlock_%=, 6b-1b\n\t"	      \ +			".previous\n"					      \ +			LLL_STUB_UNWIND_INFO_5				      \ +			"24:"						      \ +			: "=m" (futex), "=&D" (ignore)			      \ +			: "i" (FUTEX_WAITERS), "m" (futex),		      \ +			  "S" (private)					      \ +			: "ax", "cx", "r11", "cc", "memory");		      \ +    }									      \ +  while (0) + +#define lll_robust_dead(futex, private) \ +  do									      \ +    {									      \ +      int ignore;							      \ +      __asm__ __volatile (LOCK_INSTR "orl %3, (%2)\n\t"			      \ +			"syscall"					      \ +			: "=m" (futex), "=a" (ignore)			      \ +			: "D" (&(futex)), "i" (FUTEX_OWNER_DIED),	      \ +			  "S" (__lll_private_flag (FUTEX_WAKE, private)),     \ +			  "1" (__NR_futex), "d" (1)			      \ +			: "cx", "r11", "cc", "memory");			      \ +    }									      \ +  while (0) + +/* Returns non-zero if error happened, zero if success.  */ +#define lll_futex_requeue(ftx, nr_wake, nr_move, mutex, val, private) \ +  ({ int __res;								      \ +     register int __nr_move __asm__ ("r10") = nr_move;			      \ +     register void *__mutex __asm__ ("r8") = mutex;			      \ +     register int __val __asm__ ("r9") = val;				      \ +     __asm__ __volatile ("syscall"					      \ +		       : "=a" (__res)					      \ +		       : "0" (__NR_futex), "D" ((void *) ftx),		      \ +			 "S" (__lll_private_flag (FUTEX_CMP_REQUEUE,	      \ +						  private)), "d" (nr_wake),   \ +			 "r" (__nr_move), "r" (__mutex), "r" (__val)	      \ +		       : "cx", "r11", "cc", "memory");			      \ +     __res < 0; }) + +#define lll_islocked(futex) \ +  (futex != LLL_LOCK_INITIALIZER) + + +/* The kernel notifies a process with uses CLONE_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. + +   The macro parameter must not have any side effect.  */ +#define lll_wait_tid(tid) \ +  do {									      \ +    int __ignore;							      \ +    register __typeof (tid) _tid __asm__ ("edx") = (tid);			      \ +    if (_tid != 0)							      \ +      __asm__ __volatile ("xorq %%r10, %%r10\n\t"				      \ +			"1:\tmovq %2, %%rax\n\t"			      \ +			"syscall\n\t"					      \ +			"cmpl $0, (%%rdi)\n\t"				      \ +			"jne 1b"					      \ +			: "=&a" (__ignore)				      \ +			: "S" (FUTEX_WAIT), "i" (SYS_futex), "D" (&tid),      \ +			  "d" (_tid)					      \ +			: "memory", "cc", "r10", "r11", "cx");		      \ +  } while (0) + +extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime) +     attribute_hidden; +#define lll_timedwait_tid(tid, abstime) \ +  ({									      \ +    int __result = 0;							      \ +    if (tid != 0)							      \ +      {									      \ +	if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)	      \ +	  __result = EINVAL;						      \ +	else								      \ +	  __result = __lll_timedwait_tid (&tid, abstime);		      \ +      }									      \ +    __result; }) + +#endif  /* !__ASSEMBLER__ */ + +#endif	/* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.S new file mode 100644 index 000000000..2eb8e29fa --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.S @@ -0,0 +1,306 @@ +/* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2009 +   Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <pthread-errnos.h> +#include <lowlevellock.h> +#include <lowlevelrobustlock.h> +#include <bits/kernel-features.h> + +	.text + +#define FUTEX_WAITERS		0x80000000 +#define FUTEX_OWNER_DIED	0x40000000 + +#ifdef __ASSUME_PRIVATE_FUTEX +# define LOAD_FUTEX_WAIT(reg) \ +	xorl	$(FUTEX_WAIT | FUTEX_PRIVATE_FLAG), reg +# define LOAD_FUTEX_WAIT_ABS(reg) \ +	xorl	$(FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME), reg +#else +# if FUTEX_WAIT == 0 +#  define LOAD_FUTEX_WAIT(reg) \ +	xorl	$FUTEX_PRIVATE_FLAG, reg ; \ +	andl	%fs:PRIVATE_FUTEX, reg +# else +#  define LOAD_FUTEX_WAIT(reg) \ +	xorl	$FUTEX_PRIVATE_FLAG, reg ; \ +	andl	%fs:PRIVATE_FUTEX, reg ; \ +	orl	$FUTEX_WAIT, reg +# endif +# define LOAD_FUTEX_WAIT_ABS(reg) \ +	xorl	$FUTEX_PRIVATE_FLAG, reg ; \ +	andl	%fs:PRIVATE_FUTEX, reg ; \ +	orl	$FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME, reg +#endif + +/* For the calculation see asm/vsyscall.h.  */ +#define VSYSCALL_ADDR_vgettimeofday	0xffffffffff600000 + + +	.globl	__lll_robust_lock_wait +	.type	__lll_robust_lock_wait,@function +	.hidden	__lll_robust_lock_wait +	.align	16 +__lll_robust_lock_wait: +	cfi_startproc +	pushq	%r10 +	cfi_adjust_cfa_offset(8) +	pushq	%rdx +	cfi_adjust_cfa_offset(8) +	cfi_offset(%r10, -16) +	cfi_offset(%rdx, -24) + +	xorq	%r10, %r10	/* No timeout.  */ +	LOAD_FUTEX_WAIT (%esi) + +4:	movl	%eax, %edx +	orl	$FUTEX_WAITERS, %edx + +	testl	$FUTEX_OWNER_DIED, %eax +	jnz	3f + +	cmpl	%edx, %eax +	je	1f + +	LOCK +	cmpxchgl %edx, (%rdi) +	jnz	2f + +1:	movl	$SYS_futex, %eax +	syscall + +	movl	(%rdi), %eax + +2:	testl	%eax, %eax +	jne	4b + +	movl	%fs:TID, %edx +	orl	$FUTEX_WAITERS, %edx +	LOCK +	cmpxchgl %edx, (%rdi) +	jnz	4b +	/* NB:	 %rax == 0 */ + +3:	popq	%rdx +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%rdx) +	popq	%r10 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r10) +	retq +	cfi_endproc +	.size	__lll_robust_lock_wait,.-__lll_robust_lock_wait + + +	.globl	__lll_robust_timedlock_wait +	.type	__lll_robust_timedlock_wait,@function +	.hidden	__lll_robust_timedlock_wait +	.align	16 +__lll_robust_timedlock_wait: +	cfi_startproc +# ifndef __ASSUME_FUTEX_CLOCK_REALTIME +#  ifdef __PIC__ +	cmpl	$0, __have_futex_clock_realtime(%rip) +#  else +	cmpl	$0, __have_futex_clock_realtime +#  endif +	je	.Lreltmo +# endif + +	pushq	%r9 +	cfi_adjust_cfa_offset(8) +	cfi_rel_offset(%r9, 0) +	movq	%rdx, %r10 +	movl	$0xffffffff, %r9d +	LOAD_FUTEX_WAIT_ABS (%esi) + +1:	testl	$FUTEX_OWNER_DIED, %eax +	jnz	3f + +	movl	%eax, %edx +	orl	$FUTEX_WAITERS, %edx + +	cmpl	%eax, %edx +	je	5f + +	LOCK +	cmpxchgl %edx, (%rdi) +	movq	$0, %rcx	/* Must use mov to avoid changing cc.  */ +	jnz	6f + +5:	movl	$SYS_futex, %eax +	syscall +	movl	%eax, %ecx + +	movl	(%rdi), %eax + +6:	testl	%eax, %eax +	jne	2f + +	movl	%fs:TID, %edx +	orl	$FUTEX_WAITERS, %edx +	LOCK +	cmpxchgl %edx, (%rdi) +	jnz	2f + +3:	popq	%r9 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r9) +	retq + +	cfi_adjust_cfa_offset(8) +	cfi_rel_offset(%r9, 0) +	/* Check whether the time expired.  */ +2:	cmpl	$-ETIMEDOUT, %ecx +	je	4f +	cmpl	$-EINVAL, %ecx +	jne	1b + +4:	movl	%ecx, %eax +	negl	%eax +	jmp	3b +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r9) + + +# ifndef __ASSUME_FUTEX_CLOCK_REALTIME +.Lreltmo: +	/* Check for a valid timeout value.  */ +	cmpq	$1000000000, 8(%rdx) +	jae	3f + +	pushq	%r8 +	cfi_adjust_cfa_offset(8) +	pushq	%r9 +	cfi_adjust_cfa_offset(8) +	pushq	%r12 +	cfi_adjust_cfa_offset(8) +	pushq	%r13 +	cfi_adjust_cfa_offset(8) +	cfi_offset(%r8, -16) +	cfi_offset(%r9, -24) +	cfi_offset(%r12, -32) +	cfi_offset(%r13, -40) +	pushq	%rsi +	cfi_adjust_cfa_offset(8) + +	/* Stack frame for the timespec and timeval structs.  */ +	subq	$32, %rsp +	cfi_adjust_cfa_offset(32) + +	movq	%rdi, %r12 +	movq	%rdx, %r13 + +1:	movq	%rax, 16(%rsp) + +	/* Get current time.  */ +	movq	%rsp, %rdi +	xorl	%esi, %esi +	movq	$VSYSCALL_ADDR_vgettimeofday, %rax +	/* This is a regular function call, all caller-save registers +	   might be clobbered.  */ +	callq	*%rax + +	/* Compute relative timeout.  */ +	movq	8(%rsp), %rax +	movl	$1000, %edi +	mul	%rdi		/* Milli seconds to nano seconds.  */ +	movq	(%r13), %rdi +	movq	8(%r13), %rsi +	subq	(%rsp), %rdi +	subq	%rax, %rsi +	jns	4f +	addq	$1000000000, %rsi +	decq	%rdi +4:	testq	%rdi, %rdi +	js	8f		/* Time is already up.  */ + +	/* Futex call.  */ +	movq	%rdi, (%rsp)	/* Store relative timeout.  */ +	movq	%rsi, 8(%rsp) + +	movq	16(%rsp), %rdx +	movl	%edx, %eax +	orl	$FUTEX_WAITERS, %edx + +	testl	$FUTEX_OWNER_DIED, %eax +	jnz	6f + +	cmpl	%eax, %edx +	je	2f + +	LOCK +	cmpxchgl %edx, (%r12) +	movq	$0, %rcx	/* Must use mov to avoid changing cc.  */ +	jnz	5f + +2:	movq	%rsp, %r10 +	movl	32(%rsp), %esi +	LOAD_FUTEX_WAIT (%esi) +	movq	%r12, %rdi +	movl	$SYS_futex, %eax +	syscall +	movq	%rax, %rcx + +	movl	(%r12), %eax + +5:	testl	%eax, %eax +	jne	7f + +	movl	%fs:TID, %edx +	orl	$FUTEX_WAITERS, %edx +	LOCK +	cmpxchgl %edx, (%r12) +	jnz	7f + +6:	addq	$40, %rsp +	cfi_adjust_cfa_offset(-40) +	popq	%r13 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r13) +	popq	%r12 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r12) +	popq	%r9 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r9) +	popq	%r8 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r8) +	retq + +3:	movl	$EINVAL, %eax +	retq + +	cfi_adjust_cfa_offset(72) +	cfi_offset(%r8, -16) +	cfi_offset(%r9, -24) +	cfi_offset(%r12, -32) +	cfi_offset(%r13, -40) +	/* Check whether the time expired.  */ +7:	cmpl	$-ETIMEDOUT, %ecx +	jne	1b + +8:	movl	$ETIMEDOUT, %eax +	jmp	6b +#endif +	cfi_endproc +	.size	__lll_robust_timedlock_wait,.-__lll_robust_timedlock_wait diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pt-__syscall_error.c b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pt-__syscall_error.c new file mode 100644 index 000000000..2ab81490c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pt-__syscall_error.c @@ -0,0 +1 @@ +#include <../../../../../../../libc/sysdeps/linux/x86_64/__syscall_error.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pt-vfork.S new file mode 100644 index 000000000..df4949615 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pt-vfork.S @@ -0,0 +1,33 @@ +/* Copyright (C) 2004 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <tcb-offsets.h> + +#define SAVE_PID \ +	movl	%fs:PID, %esi;						      \ +	movl	%esi, %edx;						      \ +	negl	%edx;							      \ +	movl	%edx, %fs:PID + +#define RESTORE_PID \ +	testq	%rax, %rax;						      \ +	je	1f;							      \ +	movl	%esi, %fs:PID;						      \ +1: + +#include <../../../../../../../libc/sysdeps/linux/x86_64/vfork.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S new file mode 100644 index 000000000..15ad534fa --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S @@ -0,0 +1,161 @@ +/* Copyright (C) 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelbarrier.h> + + +	.text + +	.globl	pthread_barrier_wait +	.type	pthread_barrier_wait,@function +	.align	16 +pthread_barrier_wait: +	/* Get the mutex.  */ +	xorl	%eax, %eax +	movl	$1, %esi +	LOCK +	cmpxchgl %esi, MUTEX(%rdi) +	jnz	1f + +	/* One less waiter.  If this was the last one needed wake +	   everybody.  */ +2:	decl	LEFT(%rdi) +	je	3f + +	/* There are more threads to come.  */ +#if CURR_EVENT == 0 +	movl	(%rdi), %edx +#else +	movl	CURR_EVENT(%rdi), %edx +#endif + +	/* Release the mutex.  */ +	LOCK +	decl	MUTEX(%rdi) +	jne	6f + +	/* Wait for the remaining threads.  The call will return immediately +	   if the CURR_EVENT memory has meanwhile been changed.  */ +7: +#if FUTEX_WAIT == 0 +	movl	PRIVATE(%rdi), %esi +#else +	movl	$FUTEX_WAIT, %esi +	orl	PRIVATE(%rdi), %esi +#endif +	xorq	%r10, %r10 +8:	movl	$SYS_futex, %eax +	syscall + +	/* Don't return on spurious wakeups.  The syscall does not change +	   any register except %eax so there is no need to reload any of +	   them.  */ +#if CURR_EVENT == 0 +	cmpl	%edx, (%rdi) +#else +	cmpl	%edx, CURR_EVENT(%rdi) +#endif +	je	8b + +	/* Increment LEFT.  If this brings the count back to the +	   initial count unlock the object.  */ +	movl	$1, %edx +	movl	INIT_COUNT(%rdi), %eax +	LOCK +	xaddl	%edx, LEFT(%rdi) +	subl	$1, %eax +	cmpl	%eax, %edx +	jne,pt	10f + +	/* Release the mutex.  We cannot release the lock before +	   waking the waiting threads since otherwise a new thread might +	   arrive and gets waken up, too.  */ +	LOCK +	decl	MUTEX(%rdi) +	jne	9f + +10:	xorl	%eax, %eax		/* != PTHREAD_BARRIER_SERIAL_THREAD */ + +	retq + +	/* The necessary number of threads arrived.  */ +3: +#if CURR_EVENT == 0 +	incl	(%rdi) +#else +	incl	CURR_EVENT(%rdi) +#endif + +	/* Wake up all waiters.  The count is a signed number in the kernel +	   so 0x7fffffff is the highest value.  */ +	movl	$0x7fffffff, %edx +	movl	$FUTEX_WAKE, %esi +	orl	PRIVATE(%rdi), %esi +	movl	$SYS_futex, %eax +	syscall + +	/* Increment LEFT.  If this brings the count back to the +	   initial count unlock the object.  */ +	movl	$1, %edx +	movl	INIT_COUNT(%rdi), %eax +	LOCK +	xaddl	%edx, LEFT(%rdi) +	subl	$1, %eax +	cmpl	%eax, %edx +	jne,pt	5f + +	/* Release the mutex.  We cannot release the lock before +	   waking the waiting threads since otherwise a new thread might +	   arrive and gets waken up, too.  */ +	LOCK +	decl	MUTEX(%rdi) +	jne	4f + +5:	orl	$-1, %eax		/* == PTHREAD_BARRIER_SERIAL_THREAD */ + +	retq + +1:	movl	PRIVATE(%rdi), %esi +	addq	$MUTEX, %rdi +	xorl	$LLL_SHARED, %esi +	callq	__lll_lock_wait +	subq	$MUTEX, %rdi +	jmp	2b + +4:	movl	PRIVATE(%rdi), %esi +	addq	$MUTEX, %rdi +	xorl	$LLL_SHARED, %esi +	callq	__lll_unlock_wake +	jmp	5b + +6:	movl	PRIVATE(%rdi), %esi +	addq	$MUTEX, %rdi +	xorl	$LLL_SHARED, %esi +	callq	__lll_unlock_wake +	subq	$MUTEX, %rdi +	jmp	7b + +9:	movl	PRIVATE(%rdi), %esi +	addq	$MUTEX, %rdi +	xorl	$LLL_SHARED, %esi +	callq	__lll_unlock_wake +	jmp	10b +	.size	pthread_barrier_wait,.-pthread_barrier_wait diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S new file mode 100644 index 000000000..1a116cf8f --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S @@ -0,0 +1,178 @@ +/* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2009 +   Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelcond.h> +#include <bits/kernel-features.h> +#include <pthread-pi-defines.h> +#include <pthread-errnos.h> + + +	.text + +	/* int pthread_cond_broadcast (pthread_cond_t *cond) */ +	.globl	__pthread_cond_broadcast +	.type	__pthread_cond_broadcast, @function +	.protected	__pthread_cond_broadcast +	.align	16 +__pthread_cond_broadcast: + +	/* Get internal lock.  */ +	movl	$1, %esi +	xorl	%eax, %eax +	LOCK +#if cond_lock == 0 +	cmpxchgl %esi, (%rdi) +#else +	cmpxchgl %esi, cond_lock(%rdi) +#endif +	jnz	1f + +2:	addq	$cond_futex, %rdi +	movq	total_seq-cond_futex(%rdi), %r9 +	cmpq	wakeup_seq-cond_futex(%rdi), %r9 +	jna	4f + +	/* Cause all currently waiting threads to recognize they are +	   woken up.  */ +	movq	%r9, wakeup_seq-cond_futex(%rdi) +	movq	%r9, woken_seq-cond_futex(%rdi) +	addq	%r9, %r9 +	movl	%r9d, (%rdi) +	incl	broadcast_seq-cond_futex(%rdi) + +	/* Get the address of the mutex used.  */ +	movq	dep_mutex-cond_futex(%rdi), %r8 + +	/* Unlock.  */ +	LOCK +	decl	cond_lock-cond_futex(%rdi) +	jne	7f + +8:	cmpq	$-1, %r8 +	je	9f + +	/* Do not use requeue for pshared condvars.  */ +	testl	$PS_BIT, MUTEX_KIND(%r8) +	jne	9f + +	/* Requeue to a PI mutex if the PI bit is set.  */ +	movl	MUTEX_KIND(%r8), %eax +	andl	$(ROBUST_BIT|PI_BIT), %eax +	cmpl	$PI_BIT, %eax +	je	81f + +	/* Wake up all threads.  */ +#ifdef __ASSUME_PRIVATE_FUTEX +	movl	$(FUTEX_CMP_REQUEUE|FUTEX_PRIVATE_FLAG), %esi +#else +	movl	%fs:PRIVATE_FUTEX, %esi +	orl	$FUTEX_CMP_REQUEUE, %esi +#endif +	movl	$SYS_futex, %eax +	movl	$1, %edx +	movl	$0x7fffffff, %r10d +	syscall + +	/* For any kind of error, which mainly is EAGAIN, we try again +	   with WAKE.  The general test also covers running on old +	   kernels.  */ +	cmpq	$-4095, %rax +	jae	9f + +10:	xorl	%eax, %eax +	retq + +	/* Wake up all threads.  */ +81:	movl	$(FUTEX_CMP_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %esi +	movl	$SYS_futex, %eax +	movl	$1, %edx +	movl	$0x7fffffff, %r10d +	syscall + +	/* For any kind of error, which mainly is EAGAIN, we try again +	   with WAKE.  The general test also covers running on old +	   kernels.  */ +	cmpq	$-4095, %rax +	jb	10b +	jmp	9f + +	.align	16 +	/* Unlock.  */ +4:	LOCK +	decl	cond_lock-cond_futex(%rdi) +	jne	5f + +6:	xorl	%eax, %eax +	retq + +	/* Initial locking failed.  */ +1: +#if cond_lock != 0 +	addq	$cond_lock, %rdi +#endif +	cmpq	$-1, dep_mutex-cond_lock(%rdi) +	movl	$LLL_PRIVATE, %eax +	movl	$LLL_SHARED, %esi +	cmovne	%eax, %esi +	callq	__lll_lock_wait +#if cond_lock != 0 +	subq	$cond_lock, %rdi +#endif +	jmp	2b + +	/* Unlock in loop requires wakeup.  */ +5:	addq	$cond_lock-cond_futex, %rdi +	cmpq	$-1, dep_mutex-cond_lock(%rdi) +	movl	$LLL_PRIVATE, %eax +	movl	$LLL_SHARED, %esi +	cmovne	%eax, %esi +	callq	__lll_unlock_wake +	jmp	6b + +	/* Unlock in loop requires wakeup.  */ +7:	addq	$cond_lock-cond_futex, %rdi +	cmpq	$-1, %r8 +	movl	$LLL_PRIVATE, %eax +	movl	$LLL_SHARED, %esi +	cmovne	%eax, %esi +	callq	__lll_unlock_wake +	subq	$cond_lock-cond_futex, %rdi +	jmp	8b + +9:	/* The futex requeue functionality is not available.  */ +	cmpq	$-1, %r8 +	movl	$0x7fffffff, %edx +#ifdef __ASSUME_PRIVATE_FUTEX +	movl	$FUTEX_WAKE, %eax +	movl	$(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi +	cmove	%eax, %esi +#else +	movl	$0, %eax +	movl	%fs:PRIVATE_FUTEX, %esi +	cmove	%eax, %esi +	orl	$FUTEX_WAKE, %esi +#endif +	movl	$SYS_futex, %eax +	syscall +	jmp	10b +	.size	__pthread_cond_broadcast, .-__pthread_cond_broadcast +weak_alias(__pthread_cond_broadcast, pthread_cond_broadcast) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S new file mode 100644 index 000000000..9852e79fc --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S @@ -0,0 +1,161 @@ +/* Copyright (C) 2002-2005, 2007, 2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelcond.h> +#include <pthread-pi-defines.h> +#include <bits/kernel-features.h> +#include <pthread-errnos.h> + + +	.text + +	/* int pthread_cond_signal (pthread_cond_t *cond) */ +	.globl	__pthread_cond_signal +	.type	__pthread_cond_signal, @function +	.protected	__pthread_cond_signal +	.align	16 +__pthread_cond_signal: + +	/* Get internal lock.  */ +	movq	%rdi, %r8 +	movl	$1, %esi +	xorl	%eax, %eax +	LOCK +#if cond_lock == 0 +	cmpxchgl %esi, (%rdi) +#else +	cmpxchgl %esi, cond_lock(%rdi) +#endif +	jnz	1f + +2:	addq	$cond_futex, %rdi +	movq	total_seq(%r8), %rcx +	cmpq	wakeup_seq(%r8), %rcx +	jbe	4f + +	/* Bump the wakeup number.  */ +	addq	$1, wakeup_seq(%r8) +	addl	$1, (%rdi) + +	/* Wake up one thread.  */ +	cmpq	$-1, dep_mutex(%r8) +	movl	$FUTEX_WAKE_OP, %esi +	movl	$1, %edx +	movl	$SYS_futex, %eax +	je	8f + +	/* Get the address of the mutex used.  */ +	movq    dep_mutex(%r8), %rcx +	movl	MUTEX_KIND(%rcx), %r11d +	andl	$(ROBUST_BIT|PI_BIT), %r11d +	cmpl	$PI_BIT, %r11d +	je	9f + +#ifdef __ASSUME_PRIVATE_FUTEX +	movl	$(FUTEX_WAKE_OP|FUTEX_PRIVATE_FLAG), %esi +#else +	orl	%fs:PRIVATE_FUTEX, %esi +#endif + +8:	movl	$1, %r10d +#if cond_lock != 0 +	addq	$cond_lock, %r8 +#endif +	movl	$FUTEX_OP_CLEAR_WAKE_IF_GT_ONE, %r9d +	syscall +#if cond_lock != 0 +	subq	$cond_lock, %r8 +#endif +	/* For any kind of error, we try again with WAKE. +	   The general test also covers running on old kernels.  */ +	cmpq	$-4095, %rax +	jae	7f + +	xorl	%eax, %eax +	retq + +	/* Wake up one thread and requeue none in the PI Mutex case.  */ +9:	movl	$(FUTEX_CMP_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %esi +	movq	%rcx, %r8 +	xorq	%r10, %r10 +	movl	(%rdi), %r9d	// XXX Can this be right? +	syscall + +	leaq	-cond_futex(%rdi), %r8 + +	/* For any kind of error, we try again with WAKE. +	   The general test also covers running on old kernels.  */ +	cmpq	$-4095, %rax +	jb	4f + +7: +#ifdef __ASSUME_PRIVATE_FUTEX +	andl	$FUTEX_PRIVATE_FLAG, %esi +#else +	andl	%fs:PRIVATE_FUTEX, %esi +#endif +	orl	$FUTEX_WAKE, %esi +	movl	$SYS_futex, %eax +	/* %rdx should be 1 already from $FUTEX_WAKE_OP syscall. +	movl	$1, %edx  */ +	syscall + +	/* Unlock.  */ +4:	LOCK +#if cond_lock == 0 +	decl	(%r8) +#else +	decl	cond_lock(%r8) +#endif +	jne	5f + +6:	xorl	%eax, %eax +	retq + +	/* Initial locking failed.  */ +1: +#if cond_lock != 0 +	addq	$cond_lock, %rdi +#endif +	cmpq	$-1, dep_mutex-cond_lock(%rdi) +	movl	$LLL_PRIVATE, %eax +	movl	$LLL_SHARED, %esi +	cmovne	%eax, %esi +	callq	__lll_lock_wait +#if cond_lock != 0 +	subq	$cond_lock, %rdi +#endif +	jmp	2b + +	/* Unlock in loop requires wakeup.  */ +5: +	movq	%r8, %rdi +#if cond_lock != 0 +	addq	$cond_lock, %rdi +#endif +	cmpq	$-1, dep_mutex-cond_lock(%rdi) +	movl	$LLL_PRIVATE, %eax +	movl	$LLL_SHARED, %esi +	cmovne	%eax, %esi +	callq	__lll_unlock_wake +	jmp	6b +	.size	__pthread_cond_signal, .-__pthread_cond_signal +weak_alias(__pthread_cond_signal, pthread_cond_signal) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S new file mode 100644 index 000000000..3a965ad0b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S @@ -0,0 +1,804 @@ +/* Copyright (C) 2002-2005, 2007, 2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelcond.h> +#include <pthread-pi-defines.h> +#include <pthread-errnos.h> +#include <bits/kernel-features.h> +#include <tcb-offsets.h> + +/* For the calculation see asm/vsyscall.h.  */ +#define VSYSCALL_ADDR_vgettimeofday	0xffffffffff600000 + + +	.text + + +/* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, +			       const struct timespec *abstime)  */ +	.globl	__pthread_cond_timedwait +	.type	__pthread_cond_timedwait, @function +	.protected	__pthread_cond_timedwait +	.align	16 +__pthread_cond_timedwait: +.LSTARTCODE: +	cfi_startproc + +	pushq	%r12 +	cfi_adjust_cfa_offset(8) +	cfi_rel_offset(%r12, 0) +	pushq	%r13 +	cfi_adjust_cfa_offset(8) +	cfi_rel_offset(%r13, 0) +	pushq	%r14 +	cfi_adjust_cfa_offset(8) +	cfi_rel_offset(%r14, 0) +	pushq	%r15 +	cfi_adjust_cfa_offset(8) +	cfi_rel_offset(%r15, 0) +#ifdef __ASSUME_FUTEX_CLOCK_REALTIME +# define FRAME_SIZE 32 +#else +# define FRAME_SIZE 48 +#endif +	subq	$FRAME_SIZE, %rsp +	cfi_adjust_cfa_offset(FRAME_SIZE) +	cfi_remember_state + +	cmpq	$1000000000, 8(%rdx) +	movl	$EINVAL, %eax +	jae	48f + +	/* Stack frame: + +	   rsp + 48 +		    +--------------------------+ +	   rsp + 32 | timeout value            | +		    +--------------------------+ +	   rsp + 24 | old wake_seq value       | +		    +--------------------------+ +	   rsp + 16 | mutex pointer            | +		    +--------------------------+ +	   rsp +  8 | condvar pointer          | +		    +--------------------------+ +	   rsp +  4 | old broadcast_seq value  | +		    +--------------------------+ +	   rsp +  0 | old cancellation mode    | +		    +--------------------------+ +	*/ + +	cmpq	$-1, dep_mutex(%rdi) + +	/* Prepare structure passed to cancellation handler.  */ +	movq	%rdi, 8(%rsp) +	movq	%rsi, 16(%rsp) +	movq	%rdx, %r13 + +	je	22f +	movq	%rsi, dep_mutex(%rdi) + +22: +#ifndef __ASSUME_FUTEX_CLOCK_REALTIME +#  ifdef __PIC__ +	cmpl	$0, __have_futex_clock_realtime(%rip) +#  else +	cmpl	$0, __have_futex_clock_realtime +#  endif +	je	.Lreltmo +#endif + +	/* Get internal lock.  */ +	movl	$1, %esi +	xorl	%eax, %eax +	LOCK +#if cond_lock == 0 +	cmpxchgl %esi, (%rdi) +#else +	cmpxchgl %esi, cond_lock(%rdi) +#endif +	jnz	31f + +	/* Unlock the mutex.  */ +32:	movq	16(%rsp), %rdi +	xorl	%esi, %esi +	callq	__pthread_mutex_unlock_usercnt + +	testl	%eax, %eax +	jne	46f + +	movq	8(%rsp), %rdi +	incq	total_seq(%rdi) +	incl	cond_futex(%rdi) +	addl	$(1 << nwaiters_shift), cond_nwaiters(%rdi) + +	/* Get and store current wakeup_seq value.  */ +	movq	8(%rsp), %rdi +	movq	wakeup_seq(%rdi), %r9 +	movl	broadcast_seq(%rdi), %edx +	movq	%r9, 24(%rsp) +	movl	%edx, 4(%rsp) + +38:	movl	cond_futex(%rdi), %r12d + +	/* Unlock.  */ +	LOCK +#if cond_lock == 0 +	decl	(%rdi) +#else +	decl	cond_lock(%rdi) +#endif +	jne	33f + +.LcleanupSTART1: +34:	callq	__pthread_enable_asynccancel +	movl	%eax, (%rsp) + +	movq	%r13, %r10 +	movl	$FUTEX_WAIT_BITSET, %esi +	cmpq	$-1, dep_mutex(%rdi) +	je	60f + +	movq	dep_mutex(%rdi), %r8 +	/* Requeue to a non-robust PI mutex if the PI bit is set and +	the robust bit is not set.  */ +	movl	MUTEX_KIND(%r8), %eax +	andl	$(ROBUST_BIT|PI_BIT), %eax +	cmpl	$PI_BIT, %eax +	jne	61f + +	movl	$(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %esi +	xorl	%eax, %eax +	/* The following only works like this because we only support +	   two clocks, represented using a single bit.  */ +	testl	$1, cond_nwaiters(%rdi) +	movl	$FUTEX_CLOCK_REALTIME, %edx +	cmove	%edx, %eax +	orl	%eax, %esi +	movq	%r12, %rdx +	addq	$cond_futex, %rdi +	movl	$SYS_futex, %eax +	syscall + +	movl	$1, %r15d +#ifdef __ASSUME_REQUEUE_PI +	jmp	62f +#else +	cmpq	$-4095, %rax +	jnae	62f + +	subq	$cond_futex, %rdi +#endif + +61:	movl	$(FUTEX_WAIT_BITSET|FUTEX_PRIVATE_FLAG), %esi +60:	xorl	%r15d, %r15d +	xorl	%eax, %eax +	/* The following only works like this because we only support +	   two clocks, represented using a single bit.  */ +	testl	$1, cond_nwaiters(%rdi) +	movl	$FUTEX_CLOCK_REALTIME, %edx +	movl	$0xffffffff, %r9d +	cmove	%edx, %eax +	orl	%eax, %esi +	movq	%r12, %rdx +	addq	$cond_futex, %rdi +	movl	$SYS_futex, %eax +	syscall +62:	movq	%rax, %r14 + +	movl	(%rsp), %edi +	callq	__pthread_disable_asynccancel +.LcleanupEND1: + +	/* Lock.  */ +	movq	8(%rsp), %rdi +	movl	$1, %esi +	xorl	%eax, %eax +	LOCK +#if cond_lock == 0 +	cmpxchgl %esi, (%rdi) +#else +	cmpxchgl %esi, cond_lock(%rdi) +#endif +	jne	35f + +36:	movl	broadcast_seq(%rdi), %edx + +	movq	woken_seq(%rdi), %rax + +	movq	wakeup_seq(%rdi), %r9 + +	cmpl	4(%rsp), %edx +	jne	53f + +	cmpq	24(%rsp), %r9 +	jbe	45f + +	cmpq	%rax, %r9 +	ja	39f + +45:	cmpq	$-ETIMEDOUT, %r14 +	jne	38b + +99:	incq	wakeup_seq(%rdi) +	incl	cond_futex(%rdi) +	movl	$ETIMEDOUT, %r14d +	jmp	44f + +53:	xorq	%r14, %r14 +	jmp	54f + +39:	xorq	%r14, %r14 +44:	incq	woken_seq(%rdi) + +54:	subl	$(1 << nwaiters_shift), cond_nwaiters(%rdi) + +	/* Wake up a thread which wants to destroy the condvar object.  */ +	cmpq	$0xffffffffffffffff, total_seq(%rdi) +	jne	55f +	movl	cond_nwaiters(%rdi), %eax +	andl	$~((1 << nwaiters_shift) - 1), %eax +	jne	55f + +	addq	$cond_nwaiters, %rdi +	cmpq	$-1, dep_mutex-cond_nwaiters(%rdi) +	movl	$1, %edx +#ifdef __ASSUME_PRIVATE_FUTEX +	movl	$FUTEX_WAKE, %eax +	movl	$(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi +	cmove	%eax, %esi +#else +	movl	$0, %eax +	movl	%fs:PRIVATE_FUTEX, %esi +	cmove	%eax, %esi +	orl	$FUTEX_WAKE, %esi +#endif +	movl	$SYS_futex, %eax +	syscall +	subq	$cond_nwaiters, %rdi + +55:	LOCK +#if cond_lock == 0 +	decl	(%rdi) +#else +	decl	cond_lock(%rdi) +#endif +	jne	40f + +	/* If requeue_pi is used the kernel performs the locking of the +	   mutex. */ +41:	movq	16(%rsp), %rdi +	testl	%r15d, %r15d +	jnz	64f + +	callq	__pthread_mutex_cond_lock + +63:	testq	%rax, %rax +	cmoveq	%r14, %rax + +48:	addq	$FRAME_SIZE, %rsp +	cfi_adjust_cfa_offset(-FRAME_SIZE) +	popq	%r15 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r15) +	popq	%r14 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r14) +	popq	%r13 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r13) +	popq	%r12 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r12) + +	retq + +	cfi_restore_state + +64:	callq	__pthread_mutex_cond_lock_adjust +	movq	%r14, %rax +	jmp	48b + +	/* Initial locking failed.  */ +31: +#if cond_lock != 0 +	addq	$cond_lock, %rdi +#endif +	cmpq	$-1, dep_mutex-cond_lock(%rdi) +	movl	$LLL_PRIVATE, %eax +	movl	$LLL_SHARED, %esi +	cmovne	%eax, %esi +	callq	__lll_lock_wait +	jmp	32b + +	/* Unlock in loop requires wakeup.  */ +33: +#if cond_lock != 0 +	addq	$cond_lock, %rdi +#endif +	cmpq	$-1, dep_mutex-cond_lock(%rdi) +	movl	$LLL_PRIVATE, %eax +	movl	$LLL_SHARED, %esi +	cmovne	%eax, %esi +	callq	__lll_unlock_wake +	jmp	34b + +	/* Locking in loop failed.  */ +35: +#if cond_lock != 0 +	addq	$cond_lock, %rdi +#endif +	cmpq	$-1, dep_mutex-cond_lock(%rdi) +	movl	$LLL_PRIVATE, %eax +	movl	$LLL_SHARED, %esi +	cmovne	%eax, %esi +	callq	__lll_lock_wait +#if cond_lock != 0 +	subq	$cond_lock, %rdi +#endif +	jmp	36b + +	/* Unlock after loop requires wakeup.  */ +40: +#if cond_lock != 0 +	addq	$cond_lock, %rdi +#endif +	cmpq	$-1, dep_mutex-cond_lock(%rdi) +	movl	$LLL_PRIVATE, %eax +	movl	$LLL_SHARED, %esi +	cmovne	%eax, %esi +	callq	__lll_unlock_wake +	jmp	41b + +	/* The initial unlocking of the mutex failed.  */ +46:	movq	8(%rsp), %rdi +	movq	%rax, (%rsp) +	LOCK +#if cond_lock == 0 +	decl	(%rdi) +#else +	decl	cond_lock(%rdi) +#endif +	jne	47f + +#if cond_lock != 0 +	addq	$cond_lock, %rdi +#endif +	cmpq	$-1, dep_mutex-cond_lock(%rdi) +	movl	$LLL_PRIVATE, %eax +	movl	$LLL_SHARED, %esi +	cmovne	%eax, %esi +	callq	__lll_unlock_wake + +47:	movq	(%rsp), %rax +	jmp	48b + + +#ifndef __ASSUME_FUTEX_CLOCK_REALTIME +.Lreltmo: +	xorl	%r15d, %r15d + +	/* Get internal lock.  */ +	movl	$1, %esi +	xorl	%eax, %eax +	LOCK +# if cond_lock == 0 +	cmpxchgl %esi, (%rdi) +# else +	cmpxchgl %esi, cond_lock(%rdi) +# endif +	jnz	1f + +	/* Unlock the mutex.  */ +2:	movq	16(%rsp), %rdi +	xorl	%esi, %esi +	callq	__pthread_mutex_unlock_usercnt + +	testl	%eax, %eax +	jne	46b + +	movq	8(%rsp), %rdi +	incq	total_seq(%rdi) +	incl	cond_futex(%rdi) +	addl	$(1 << nwaiters_shift), cond_nwaiters(%rdi) + +	/* Get and store current wakeup_seq value.  */ +	movq	8(%rsp), %rdi +	movq	wakeup_seq(%rdi), %r9 +	movl	broadcast_seq(%rdi), %edx +	movq	%r9, 24(%rsp) +	movl	%edx, 4(%rsp) + +	/* Get the current time.  */ +8: +# ifdef __NR_clock_gettime +	/* Get the clock number.  Note that the field in the condvar +	   structure stores the number minus 1.  */ +	movq	8(%rsp), %rdi +	movl	cond_nwaiters(%rdi), %edi +	andl	$((1 << nwaiters_shift) - 1), %edi +	/* Only clocks 0 and 1 are allowed so far.  Both are handled in the +	   kernel.  */ +	leaq	32(%rsp), %rsi +#  ifdef SHARED +	movq	__vdso_clock_gettime@GOTPCREL(%rip), %rax +	movq	(%rax), %rax +	PTR_DEMANGLE (%rax) +	jz	26f +	call	*%rax +	jmp	27f +#  endif +26:	movl	$__NR_clock_gettime, %eax +	syscall +27: +#  ifndef __ASSUME_POSIX_TIMERS +	cmpq	$-ENOSYS, %rax +	je	19f +#  endif + +	/* Compute relative timeout.  */ +	movq	(%r13), %rcx +	movq	8(%r13), %rdx +	subq	32(%rsp), %rcx +	subq	40(%rsp), %rdx +# else +	leaq	24(%rsp), %rdi +	xorl	%esi, %esi +	movq	$VSYSCALL_ADDR_vgettimeofday, %rax +	callq	*%rax + +	/* Compute relative timeout.  */ +	movq	40(%rsp), %rax +	movl	$1000, %edx +	mul	%rdx		/* Milli seconds to nano seconds.  */ +	movq	(%r13), %rcx +	movq	8(%r13), %rdx +	subq	32(%rsp), %rcx +	subq	%rax, %rdx +# endif +	jns	12f +	addq	$1000000000, %rdx +	decq	%rcx +12:	testq	%rcx, %rcx +	movq	8(%rsp), %rdi +	movq	$-ETIMEDOUT, %r14 +	js	6f + +	/* Store relative timeout.  */ +21:	movq	%rcx, 32(%rsp) +	movq	%rdx, 40(%rsp) + +	movl	cond_futex(%rdi), %r12d + +	/* Unlock.  */ +	LOCK +# if cond_lock == 0 +	decl	(%rdi) +# else +	decl	cond_lock(%rdi) +# endif +	jne	3f + +.LcleanupSTART2: +4:	callq	__pthread_enable_asynccancel +	movl	%eax, (%rsp) + +	leaq	32(%rsp), %r10 +	cmpq	$-1, dep_mutex(%rdi) +	movq	%r12, %rdx +# ifdef __ASSUME_PRIVATE_FUTEX +	movl	$FUTEX_WAIT, %eax +	movl	$(FUTEX_WAIT|FUTEX_PRIVATE_FLAG), %esi +	cmove	%eax, %esi +# else +	movl	$0, %eax +	movl	%fs:PRIVATE_FUTEX, %esi +	cmove	%eax, %esi +#  if FUTEX_WAIT != 0 +	orl	$FUTEX_WAIT, %esi +#  endif +# endif +	addq	$cond_futex, %rdi +	movl	$SYS_futex, %eax +	syscall +	movq	%rax, %r14 + +	movl	(%rsp), %edi +	callq	__pthread_disable_asynccancel +.LcleanupEND2: + +	/* Lock.  */ +	movq	8(%rsp), %rdi +	movl	$1, %esi +	xorl	%eax, %eax +	LOCK +# if cond_lock == 0 +	cmpxchgl %esi, (%rdi) +# else +	cmpxchgl %esi, cond_lock(%rdi) +# endif +	jne	5f + +6:	movl	broadcast_seq(%rdi), %edx + +	movq	woken_seq(%rdi), %rax + +	movq	wakeup_seq(%rdi), %r9 + +	cmpl	4(%rsp), %edx +	jne	53b + +	cmpq	24(%rsp), %r9 +	jbe	15f + +	cmpq	%rax, %r9 +	ja	39b + +15:	cmpq	$-ETIMEDOUT, %r14 +	jne	8b + +	jmp	99b + +	/* Initial locking failed.  */ +1: +# if cond_lock != 0 +	addq	$cond_lock, %rdi +# endif +	cmpq	$-1, dep_mutex-cond_lock(%rdi) +	movl	$LLL_PRIVATE, %eax +	movl	$LLL_SHARED, %esi +	cmovne	%eax, %esi +	callq	__lll_lock_wait +	jmp	2b + +	/* Unlock in loop requires wakeup.  */ +3: +# if cond_lock != 0 +	addq	$cond_lock, %rdi +# endif +	cmpq	$-1, dep_mutex-cond_lock(%rdi) +	movl	$LLL_PRIVATE, %eax +	movl	$LLL_SHARED, %esi +	cmovne	%eax, %esi +	callq	__lll_unlock_wake +	jmp	4b + +	/* Locking in loop failed.  */ +5: +# if cond_lock != 0 +	addq	$cond_lock, %rdi +# endif +	cmpq	$-1, dep_mutex-cond_lock(%rdi) +	movl	$LLL_PRIVATE, %eax +	movl	$LLL_SHARED, %esi +	cmovne	%eax, %esi +	callq	__lll_lock_wait +# if cond_lock != 0 +	subq	$cond_lock, %rdi +# endif +	jmp	6b + +# if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS +	/* clock_gettime not available.  */ +19:	leaq	32(%rsp), %rdi +	xorl	%esi, %esi +	movq	$VSYSCALL_ADDR_vgettimeofday, %rax +	callq	*%rax + +	/* Compute relative timeout.  */ +	movq	40(%rsp), %rax +	movl	$1000, %edx +	mul	%rdx		/* Milli seconds to nano seconds.  */ +	movq	(%r13), %rcx +	movq	8(%r13), %rdx +	subq	32(%rsp), %rcx +	subq	%rax, %rdx +	jns	20f +	addq	$1000000000, %rdx +	decq	%rcx +20:	testq	%rcx, %rcx +	movq	8(%rsp), %rdi +	movq	$-ETIMEDOUT, %r14 +	js	6b +	jmp	21b +# endif +#endif +	.size	__pthread_cond_timedwait, .-__pthread_cond_timedwait +weak_alias(__pthread_cond_timedwait, pthread_cond_timedwait) + + +	.align	16 +	.type	__condvar_cleanup2, @function +__condvar_cleanup2: +	/* Stack frame: + +	   rsp + 72 +		    +--------------------------+ +	   rsp + 64 | %r12                     | +		    +--------------------------+ +	   rsp + 56 | %r13                     | +		    +--------------------------+ +	   rsp + 48 | %r14                     | +		    +--------------------------+ +	   rsp + 24 | unused                   | +		    +--------------------------+ +	   rsp + 16 | mutex pointer            | +		    +--------------------------+ +	   rsp +  8 | condvar pointer          | +		    +--------------------------+ +	   rsp +  4 | old broadcast_seq value  | +		    +--------------------------+ +	   rsp +  0 | old cancellation mode    | +		    +--------------------------+ +	*/ + +	movq	%rax, 24(%rsp) + +	/* Get internal lock.  */ +	movq	8(%rsp), %rdi +	movl	$1, %esi +	xorl	%eax, %eax +	LOCK +#if cond_lock == 0 +	cmpxchgl %esi, (%rdi) +#else +	cmpxchgl %esi, cond_lock(%rdi) +#endif +	jz	1f + +#if cond_lock != 0 +	addq	$cond_lock, %rdi +#endif +	cmpq	$-1, dep_mutex-cond_lock(%rdi) +	movl	$LLL_PRIVATE, %eax +	movl	$LLL_SHARED, %esi +	cmovne	%eax, %esi +	callq	__lll_lock_wait +#if cond_lock != 0 +	subq	$cond_lock, %rdi +#endif + +1:	movl	broadcast_seq(%rdi), %edx +	cmpl	4(%rsp), %edx +	jne	3f + +	/* We increment the wakeup_seq counter only if it is lower than +	   total_seq.  If this is not the case the thread was woken and +	   then canceled.  In this case we ignore the signal.  */ +	movq	total_seq(%rdi), %rax +	cmpq	wakeup_seq(%rdi), %rax +	jbe	6f +	incq	wakeup_seq(%rdi) +	incl	cond_futex(%rdi) +6:	incq	woken_seq(%rdi) + +3:	subl	$(1 << nwaiters_shift), cond_nwaiters(%rdi) + +	/* Wake up a thread which wants to destroy the condvar object.  */ +	xorq	%r12, %r12 +	cmpq	$0xffffffffffffffff, total_seq(%rdi) +	jne	4f +	movl	cond_nwaiters(%rdi), %eax +	andl	$~((1 << nwaiters_shift) - 1), %eax +	jne	4f + +	cmpq	$-1, dep_mutex(%rdi) +	leaq	cond_nwaiters(%rdi), %rdi +	movl	$1, %edx +#ifdef __ASSUME_PRIVATE_FUTEX +	movl	$FUTEX_WAKE, %eax +	movl	$(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi +	cmove	%eax, %esi +#else +	movl	$0, %eax +	movl	%fs:PRIVATE_FUTEX, %esi +	cmove	%eax, %esi +	orl	$FUTEX_WAKE, %esi +#endif +	movl	$SYS_futex, %eax +	syscall +	subq	$cond_nwaiters, %rdi +	movl	$1, %r12d + +4:	LOCK +#if cond_lock == 0 +	decl	(%rdi) +#else +	decl	cond_lock(%rdi) +#endif +	je	2f +#if cond_lock != 0 +	addq	$cond_lock, %rdi +#endif +	cmpq	$-1, dep_mutex-cond_lock(%rdi) +	movl	$LLL_PRIVATE, %eax +	movl	$LLL_SHARED, %esi +	cmovne	%eax, %esi +	callq	__lll_unlock_wake + +	/* Wake up all waiters to make sure no signal gets lost.  */ +2:	testq	%r12, %r12 +	jnz	5f +	addq	$cond_futex, %rdi +	cmpq	$-1, dep_mutex-cond_futex(%rdi) +	movl	$0x7fffffff, %edx +#ifdef __ASSUME_PRIVATE_FUTEX +	movl	$FUTEX_WAKE, %eax +	movl	$(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi +	cmove	%eax, %esi +#else +	movl	$0, %eax +	movl	%fs:PRIVATE_FUTEX, %esi +	cmove	%eax, %esi +	orl	$FUTEX_WAKE, %esi +#endif +	movl	$SYS_futex, %eax +	syscall + +5:	movq	16(%rsp), %rdi +	callq	__pthread_mutex_cond_lock + +	movq	24(%rsp), %rdi +	movq	FRAME_SIZE(%rsp), %r15 +	movq	FRAME_SIZE+8(%rsp), %r14 +	movq	FRAME_SIZE+16(%rsp), %r13 +	movq	FRAME_SIZE+24(%rsp), %r12 +.LcallUR: +	call	_Unwind_Resume@PLT +	hlt +.LENDCODE: +	cfi_endproc +	.size	__condvar_cleanup2, .-__condvar_cleanup2 + + +	.section .gcc_except_table,"a",@progbits +.LexceptSTART: +	.byte	DW_EH_PE_omit			# @LPStart format +	.byte	DW_EH_PE_omit			# @TType format +	.byte	DW_EH_PE_uleb128		# call-site format +	.uleb128 .Lcstend-.Lcstbegin +.Lcstbegin: +	.uleb128 .LcleanupSTART1-.LSTARTCODE +	.uleb128 .LcleanupEND1-.LcleanupSTART1 +	.uleb128 __condvar_cleanup2-.LSTARTCODE +	.uleb128  0 +#ifndef __ASSUME_FUTEX_CLOCK_REALTIME +	.uleb128 .LcleanupSTART2-.LSTARTCODE +	.uleb128 .LcleanupEND2-.LcleanupSTART2 +	.uleb128 __condvar_cleanup2-.LSTARTCODE +	.uleb128  0 +#endif +	.uleb128 .LcallUR-.LSTARTCODE +	.uleb128 .LENDCODE-.LcallUR +	.uleb128 0 +	.uleb128  0 +.Lcstend: + + +#ifdef SHARED +	.hidden	DW.ref.__gcc_personality_v0 +	.weak	DW.ref.__gcc_personality_v0 +	.section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits +	.align	8 +	.type	DW.ref.__gcc_personality_v0, @object +	.size	DW.ref.__gcc_personality_v0, 8 +DW.ref.__gcc_personality_v0: +	.quad	__gcc_personality_v0 +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S new file mode 100644 index 000000000..cc67ed9de --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S @@ -0,0 +1,487 @@ +/* Copyright (C) 2002-2007, 2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelcond.h> +#include <tcb-offsets.h> +#include <pthread-pi-defines.h> + +#include <bits/kernel-features.h> + + +	.text + +/* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)  */ +	.globl	__pthread_cond_wait +	.type	__pthread_cond_wait, @function +	.protected	__pthread_cond_wait +	.align	16 +__pthread_cond_wait: +.LSTARTCODE: +	cfi_startproc + +#define FRAME_SIZE 32 +	leaq	-FRAME_SIZE(%rsp), %rsp +	cfi_adjust_cfa_offset(FRAME_SIZE) + +	/* Stack frame: + +	   rsp + 32 +		    +--------------------------+ +	   rsp + 24 | old wake_seq value       | +	            +--------------------------+ +	   rsp + 16 | mutex pointer            | +	            +--------------------------+ +	   rsp +  8 | condvar pointer          | +	            +--------------------------+ +	   rsp +  4 | old broadcast_seq value  | +	            +--------------------------+ +	   rsp +  0 | old cancellation mode    | +	            +--------------------------+ +	*/ + +	cmpq	$-1, dep_mutex(%rdi) + +		/* Prepare structure passed to cancellation handler.  */ +	movq	%rdi, 8(%rsp) +	movq	%rsi, 16(%rsp) + +	je	15f +	movq	%rsi, dep_mutex(%rdi) + +	/* Get internal lock.  */ +15:	movl	$1, %esi +	xorl	%eax, %eax +	LOCK +#if cond_lock == 0 +	cmpxchgl %esi, (%rdi) +#else +	cmpxchgl %esi, cond_lock(%rdi) +#endif +	jne	1f + +	/* Unlock the mutex.  */ +2:	movq	16(%rsp), %rdi +	xorl	%esi, %esi +	callq	__pthread_mutex_unlock_usercnt + +	testl	%eax, %eax +	jne	12f + +	movq	8(%rsp), %rdi +	incq	total_seq(%rdi) +	incl	cond_futex(%rdi) +	addl	$(1 << nwaiters_shift), cond_nwaiters(%rdi) + +	/* Get and store current wakeup_seq value.  */ +	movq	8(%rsp), %rdi +	movq	wakeup_seq(%rdi), %r9 +	movl	broadcast_seq(%rdi), %edx +	movq	%r9, 24(%rsp) +	movl	%edx, 4(%rsp) + +	/* Unlock.  */ +8:	movl	cond_futex(%rdi), %edx +	LOCK +#if cond_lock == 0 +	decl	(%rdi) +#else +	decl	cond_lock(%rdi) +#endif +	jne	3f + +.LcleanupSTART: +4:	callq	__pthread_enable_asynccancel +	movl	%eax, (%rsp) + +	xorq	%r10, %r10 +	cmpq	$-1, dep_mutex(%rdi) +	leaq	cond_futex(%rdi), %rdi +	movl	$FUTEX_WAIT, %esi +	je	60f + +	movq	dep_mutex-cond_futex(%rdi), %r8 +	/* Requeue to a non-robust PI mutex if the PI bit is set and +	the robust bit is not set.  */ +	movl	MUTEX_KIND(%r8), %eax +	andl	$(ROBUST_BIT|PI_BIT), %eax +	cmpl	$PI_BIT, %eax +	jne	61f + +	movl	$(FUTEX_WAIT_REQUEUE_PI|FUTEX_PRIVATE_FLAG), %esi +	movl	$SYS_futex, %eax +	syscall + +	movl	$1, %r8d +#ifdef __ASSUME_REQUEUE_PI +	jmp	62f +#else +	cmpq	$-4095, %rax +	jnae	62f + +# ifndef __ASSUME_PRIVATE_FUTEX +	movl	$FUTEX_WAIT, %esi +# endif +#endif + +61: +#ifdef __ASSUME_PRIVATE_FUTEX +	movl	$(FUTEX_WAIT|FUTEX_PRIVATE_FLAG), %esi +#else +	orl	%fs:PRIVATE_FUTEX, %esi +#endif +60:	xorl	%r8d, %r8d +	movl	$SYS_futex, %eax +	syscall + +62:	movl	(%rsp), %edi +	callq	__pthread_disable_asynccancel +.LcleanupEND: + +	/* Lock.  */ +	movq	8(%rsp), %rdi +	movl	$1, %esi +	xorl	%eax, %eax +	LOCK +#if cond_lock == 0 +	cmpxchgl %esi, (%rdi) +#else +	cmpxchgl %esi, cond_lock(%rdi) +#endif +	jnz	5f + +6:	movl	broadcast_seq(%rdi), %edx + +	movq	woken_seq(%rdi), %rax + +	movq	wakeup_seq(%rdi), %r9 + +	cmpl	4(%rsp), %edx +	jne	16f + +	cmpq	24(%rsp), %r9 +	jbe	8b + +	cmpq	%rax, %r9 +	jna	8b + +	incq	woken_seq(%rdi) + +	/* Unlock */ +16:	subl	$(1 << nwaiters_shift), cond_nwaiters(%rdi) + +	/* Wake up a thread which wants to destroy the condvar object.  */ +	cmpq	$0xffffffffffffffff, total_seq(%rdi) +	jne	17f +	movl	cond_nwaiters(%rdi), %eax +	andl	$~((1 << nwaiters_shift) - 1), %eax +	jne	17f + +	addq	$cond_nwaiters, %rdi +	cmpq	$-1, dep_mutex-cond_nwaiters(%rdi) +	movl	$1, %edx +#ifdef __ASSUME_PRIVATE_FUTEX +	movl	$FUTEX_WAKE, %eax +	movl	$(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi +	cmove	%eax, %esi +#else +	movl	$0, %eax +	movl	%fs:PRIVATE_FUTEX, %esi +	cmove	%eax, %esi +	orl	$FUTEX_WAKE, %esi +#endif +	movl	$SYS_futex, %eax +	syscall +	subq	$cond_nwaiters, %rdi + +17:	LOCK +#if cond_lock == 0 +	decl	(%rdi) +#else +	decl	cond_lock(%rdi) +#endif +	jne	10f + +	/* If requeue_pi is used the kernel performs the locking of the +	   mutex. */ +11:	movq	16(%rsp), %rdi +	testl	%r8d, %r8d +	jnz	18f + +	callq	__pthread_mutex_cond_lock + +14:	leaq	FRAME_SIZE(%rsp), %rsp +	cfi_adjust_cfa_offset(-FRAME_SIZE) + +	/* We return the result of the mutex_lock operation.  */ +	retq + +	cfi_adjust_cfa_offset(FRAME_SIZE) + +18:	callq	__pthread_mutex_cond_lock_adjust +	xorl	%eax, %eax +	jmp	14b + +	/* Initial locking failed.  */ +1: +#if cond_lock != 0 +	addq	$cond_lock, %rdi +#endif +	cmpq	$-1, dep_mutex-cond_lock(%rdi) +	movl	$LLL_PRIVATE, %eax +	movl	$LLL_SHARED, %esi +	cmovne	%eax, %esi +	callq	__lll_lock_wait +	jmp	2b + +	/* Unlock in loop requires wakeup.  */ +3: +#if cond_lock != 0 +	addq	$cond_lock, %rdi +#endif +	cmpq	$-1, dep_mutex-cond_lock(%rdi) +	movl	$LLL_PRIVATE, %eax +	movl	$LLL_SHARED, %esi +	cmovne	%eax, %esi +	/* The call preserves %rdx.  */ +	callq	__lll_unlock_wake +#if cond_lock != 0 +	subq	$cond_lock, %rdi +#endif +	jmp	4b + +	/* Locking in loop failed.  */ +5: +#if cond_lock != 0 +	addq	$cond_lock, %rdi +#endif +	cmpq	$-1, dep_mutex-cond_lock(%rdi) +	movl	$LLL_PRIVATE, %eax +	movl	$LLL_SHARED, %esi +	cmovne	%eax, %esi +	callq	__lll_lock_wait +#if cond_lock != 0 +	subq	$cond_lock, %rdi +#endif +	jmp	6b + +	/* Unlock after loop requires wakeup.  */ +10: +#if cond_lock != 0 +	addq	$cond_lock, %rdi +#endif +	cmpq	$-1, dep_mutex-cond_lock(%rdi) +	movl	$LLL_PRIVATE, %eax +	movl	$LLL_SHARED, %esi +	cmovne	%eax, %esi +	callq	__lll_unlock_wake +	jmp	11b + +	/* The initial unlocking of the mutex failed.  */ +12:	movq	%rax, %r10 +	movq	8(%rsp), %rdi +	LOCK +#if cond_lock == 0 +	decl	(%rdi) +#else +	decl	cond_lock(%rdi) +#endif +	je	13f + +#if cond_lock != 0 +	addq	$cond_lock, %rdi +#endif +	cmpq	$-1, dep_mutex-cond_lock(%rdi) +	movl	$LLL_PRIVATE, %eax +	movl	$LLL_SHARED, %esi +	cmovne	%eax, %esi +	callq	__lll_unlock_wake + +13:	movq	%r10, %rax +	jmp	14b +	.size	__pthread_cond_wait, .-__pthread_cond_wait +weak_alias(__pthread_cond_wait, pthread_cond_wait) + + +	.align	16 +	.type	__condvar_cleanup1, @function +	.globl	__condvar_cleanup1 +	.hidden	__condvar_cleanup1 +__condvar_cleanup1: +	/* Stack frame: + +	   rsp + 32 +		    +--------------------------+ +	   rsp + 24 | unused                   | +	            +--------------------------+ +	   rsp + 16 | mutex pointer            | +	            +--------------------------+ +	   rsp +  8 | condvar pointer          | +	            +--------------------------+ +	   rsp +  4 | old broadcast_seq value  | +	            +--------------------------+ +	   rsp +  0 | old cancellation mode    | +	            +--------------------------+ +	*/ + +	movq	%rax, 24(%rsp) + +	/* Get internal lock.  */ +	movq	8(%rsp), %rdi +	movl	$1, %esi +	xorl	%eax, %eax +	LOCK +#if cond_lock == 0 +	cmpxchgl %esi, (%rdi) +#else +	cmpxchgl %esi, cond_lock(%rdi) +#endif +	jz	1f + +#if cond_lock != 0 +	addq	$cond_lock, %rdi +#endif +	cmpq	$-1, dep_mutex-cond_lock(%rdi) +	movl	$LLL_PRIVATE, %eax +	movl	$LLL_SHARED, %esi +	cmovne	%eax, %esi +	callq	__lll_lock_wait +#if cond_lock != 0 +	subq	$cond_lock, %rdi +#endif + +1:	movl	broadcast_seq(%rdi), %edx +	cmpl	4(%rsp), %edx +	jne	3f + +	/* We increment the wakeup_seq counter only if it is lower than +	   total_seq.  If this is not the case the thread was woken and +	   then canceled.  In this case we ignore the signal.  */ +	movq	total_seq(%rdi), %rax +	cmpq	wakeup_seq(%rdi), %rax +	jbe	6f +	incq	wakeup_seq(%rdi) +	incl	cond_futex(%rdi) +6:	incq	woken_seq(%rdi) + +3:	subl	$(1 << nwaiters_shift), cond_nwaiters(%rdi) + +	/* Wake up a thread which wants to destroy the condvar object.  */ +	xorl	%ecx, %ecx +	cmpq	$0xffffffffffffffff, total_seq(%rdi) +	jne	4f +	movl	cond_nwaiters(%rdi), %eax +	andl	$~((1 << nwaiters_shift) - 1), %eax +	jne	4f + +	cmpq	$-1, dep_mutex(%rdi) +	leaq	cond_nwaiters(%rdi), %rdi +	movl	$1, %edx +#ifdef __ASSUME_PRIVATE_FUTEX +	movl	$FUTEX_WAKE, %eax +	movl	$(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi +	cmove	%eax, %esi +#else +	movl	$0, %eax +	movl	%fs:PRIVATE_FUTEX, %esi +	cmove	%eax, %esi +	orl	$FUTEX_WAKE, %esi +#endif +	movl	$SYS_futex, %eax +	syscall +	subq	$cond_nwaiters, %rdi +	movl	$1, %ecx + +4:	LOCK +#if cond_lock == 0 +	decl	(%rdi) +#else +	decl	cond_lock(%rdi) +#endif +	je	2f +#if cond_lock != 0 +	addq	$cond_lock, %rdi +#endif +	cmpq	$-1, dep_mutex-cond_lock(%rdi) +	movl	$LLL_PRIVATE, %eax +	movl	$LLL_SHARED, %esi +	cmovne	%eax, %esi +	/* The call preserves %rcx.  */ +	callq	__lll_unlock_wake + +	/* Wake up all waiters to make sure no signal gets lost.  */ +2:	testl	%ecx, %ecx +	jnz	5f +	addq	$cond_futex, %rdi +	cmpq	$-1, dep_mutex-cond_futex(%rdi) +	movl	$0x7fffffff, %edx +#ifdef __ASSUME_PRIVATE_FUTEX +	movl	$FUTEX_WAKE, %eax +	movl	$(FUTEX_WAKE|FUTEX_PRIVATE_FLAG), %esi +	cmove	%eax, %esi +#else +	movl	$0, %eax +	movl	%fs:PRIVATE_FUTEX, %esi +	cmove	%eax, %esi +	orl	$FUTEX_WAKE, %esi +#endif +	movl	$SYS_futex, %eax +	syscall + +5:	movq	16(%rsp), %rdi +	callq	__pthread_mutex_cond_lock + +	movq	24(%rsp), %rdi +.LcallUR: +	call	_Unwind_Resume@PLT +	hlt +.LENDCODE: +	cfi_endproc +	.size	__condvar_cleanup1, .-__condvar_cleanup1 + + +	.section .gcc_except_table,"a",@progbits +.LexceptSTART: +	.byte	DW_EH_PE_omit			# @LPStart format +	.byte	DW_EH_PE_omit			# @TType format +	.byte	DW_EH_PE_uleb128		# call-site format +	.uleb128 .Lcstend-.Lcstbegin +.Lcstbegin: +	.uleb128 .LcleanupSTART-.LSTARTCODE +	.uleb128 .LcleanupEND-.LcleanupSTART +	.uleb128 __condvar_cleanup1-.LSTARTCODE +	.uleb128  0 +	.uleb128 .LcallUR-.LSTARTCODE +	.uleb128 .LENDCODE-.LcallUR +	.uleb128 0 +	.uleb128  0 +.Lcstend: + + +#ifdef SHARED +	.hidden	DW.ref.__gcc_personality_v0 +	.weak	DW.ref.__gcc_personality_v0 +	.section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits +	.align	8 +	.type	DW.ref.__gcc_personality_v0, @object +	.size	DW.ref.__gcc_personality_v0, 8 +DW.ref.__gcc_personality_v0: +	.quad	__gcc_personality_v0 +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S new file mode 100644 index 000000000..9013d8fa0 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S @@ -0,0 +1,190 @@ +/* Copyright (C) 2002, 2003, 2005, 2007, 2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <bits/kernel-features.h> +#include <tcb-offsets.h> +#include <lowlevellock.h> + + +	.comm	__fork_generation, 4, 4 + +	.text + + +	.globl	__pthread_once +	.type	__pthread_once,@function +	.protected	__pthread_once +	.align	16 +__pthread_once: +.LSTARTCODE: +	cfi_startproc +	testl	$2, (%rdi) +	jz	1f +	xorl	%eax, %eax +	retq + +	/* Preserve the function pointer.  */ +1:	pushq	%rsi +	cfi_adjust_cfa_offset(8) +	xorq	%r10, %r10 + +	/* Not yet initialized or initialization in progress. +	   Get the fork generation counter now.  */ +6:	movl	(%rdi), %eax + +5:	movl	%eax, %edx + +	testl	$2, %eax +	jnz	4f + +	andl	$3, %edx +	orl	__fork_generation(%rip), %edx +	orl	$1, %edx + +	LOCK +	cmpxchgl %edx, (%rdi) +	jnz	5b + +	/* Check whether another thread already runs the initializer.  */ +	testl	$1, %eax +	jz	3f	/* No -> do it.  */ + +	/* Check whether the initializer execution was interrupted +	   by a fork.  */ +	xorl	%edx, %eax +	testl	$0xfffffffc, %eax +	jnz	3f	/* Different for generation -> run initializer.  */ + +	/* Somebody else got here first.  Wait.  */ +#ifdef __ASSUME_PRIVATE_FUTEX +	movl	$FUTEX_WAIT|FUTEX_PRIVATE_FLAG, %esi +#else +# if FUTEX_WAIT == 0 +	movl	%fs:PRIVATE_FUTEX, %esi +# else +	movl	$FUTEX_WAIT, %esi +	orl	%fs:PRIVATE_FUTEX, %esi +# endif +#endif +	movl	$SYS_futex, %eax +	syscall +	jmp	6b + +	/* Preserve the pointer to the control variable.  */ +3:	pushq	%rdi +	cfi_adjust_cfa_offset(8) +	pushq	%rdi +	cfi_adjust_cfa_offset(8) + +.LcleanupSTART: +	callq	*16(%rsp) +.LcleanupEND: + +	/* Get the control variable address back.  */ +	popq	%rdi +	cfi_adjust_cfa_offset(-8) + +	/* Sucessful run of the initializer.  Signal that we are done.  */ +	LOCK +	incl	(%rdi) + +	addq	$8, %rsp +	cfi_adjust_cfa_offset(-8) + +	/* Wake up all other threads.  */ +	movl	$0x7fffffff, %edx +#ifdef __ASSUME_PRIVATE_FUTEX +	movl	$FUTEX_WAKE|FUTEX_PRIVATE_FLAG, %esi +#else +	movl	$FUTEX_WAKE, %esi +	orl	%fs:PRIVATE_FUTEX, %esi +#endif +	movl	$SYS_futex, %eax +	syscall + +4:	addq	$8, %rsp +	cfi_adjust_cfa_offset(-8) +	xorl	%eax, %eax +	retq +	.size	__pthread_once,.-__pthread_once + + +	.globl	__pthread_once_internal +__pthread_once_internal = __pthread_once + +	.globl	pthread_once +pthread_once = __pthread_once + + +	.type	clear_once_control,@function +	.align	16 +clear_once_control: +	cfi_adjust_cfa_offset(3 * 8) +	movq	(%rsp), %rdi +	movq	%rax, %r8 +	movl	$0, (%rdi) + +	movl	$0x7fffffff, %edx +#ifdef __ASSUME_PRIVATE_FUTEX +	movl	$FUTEX_WAKE|FUTEX_PRIVATE_FLAG, %esi +#else +	movl	$FUTEX_WAKE, %esi +	orl	%fs:PRIVATE_FUTEX, %esi +#endif +	movl	$SYS_futex, %eax +	syscall + +	movq	%r8, %rdi +.LcallUR: +	call	_Unwind_Resume@PLT +	hlt +.LENDCODE: +	cfi_endproc +	.size	clear_once_control,.-clear_once_control + + +	.section .gcc_except_table,"a",@progbits +.LexceptSTART: +	.byte	DW_EH_PE_omit			# @LPStart format +	.byte	DW_EH_PE_omit			# @TType format +	.byte	DW_EH_PE_uleb128		# call-site format +	.uleb128 .Lcstend-.Lcstbegin +.Lcstbegin: +	.uleb128 .LcleanupSTART-.LSTARTCODE +	.uleb128 .LcleanupEND-.LcleanupSTART +	.uleb128 clear_once_control-.LSTARTCODE +	.uleb128  0 +	.uleb128 .LcallUR-.LSTARTCODE +	.uleb128 .LENDCODE-.LcallUR +	.uleb128 0 +	.uleb128  0 +.Lcstend: + + +#ifdef SHARED +	.hidden	DW.ref.__gcc_personality_v0 +	.weak	DW.ref.__gcc_personality_v0 +	.section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits +	.align	8 +	.type	DW.ref.__gcc_personality_v0, @object +	.size	DW.ref.__gcc_personality_v0, 8 +DW.ref.__gcc_personality_v0: +	.quad	__gcc_personality_v0 +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S new file mode 100644 index 000000000..82badb1ee --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S @@ -0,0 +1,180 @@ +/* Copyright (C) 2002, 2003, 2005, 2007, 2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <bits/kernel-features.h> +#include <tcb-offsets.h> + + +	.text + +	.globl	__pthread_rwlock_rdlock +	.type	__pthread_rwlock_rdlock,@function +	.protected	__pthread_rwlock_rdlock +	.align	16 +__pthread_rwlock_rdlock: +	cfi_startproc +	xorq	%r10, %r10 + +	/* Get the lock.  */ +	movl	$1, %esi +	xorl	%eax, %eax +	LOCK +#if MUTEX == 0 +	cmpxchgl %esi, (%rdi) +#else +	cmpxchgl %esi, MUTEX(%rdi) +#endif +	jnz	1f + +2:	movl	WRITER(%rdi), %eax +	testl	%eax, %eax +	jne	14f +	cmpl	$0, WRITERS_QUEUED(%rdi) +	je	5f +	cmpl	$0, FLAGS(%rdi) +	je	5f + +3:	incl	READERS_QUEUED(%rdi) +	je	4f + +	movl	READERS_WAKEUP(%rdi), %edx + +	LOCK +#if MUTEX == 0 +	decl	(%rdi) +#else +	decl	MUTEX(%rdi) +#endif +	jne	10f + +11: +#ifdef __ASSUME_PRIVATE_FUTEX +	movl	$FUTEX_PRIVATE_FLAG|FUTEX_WAIT, %esi +	xorl	PSHARED(%rdi), %esi +#else +# if FUTEX_WAIT == 0 +	movl	PSHARED(%rdi), %esi +# else +	movl	$FUTEX_WAIT, %esi +	orl	PSHARED(%rdi), %esi +# endif +	xorl	%fs:PRIVATE_FUTEX, %esi +#endif +	addq	$READERS_WAKEUP, %rdi +	movl	$SYS_futex, %eax +	syscall + +	subq	$READERS_WAKEUP, %rdi + +	/* Reget the lock.  */ +	movl	$1, %esi +	xorl	%eax, %eax +	LOCK +#if MUTEX == 0 +	cmpxchgl %esi, (%rdi) +#else +	cmpxchgl %esi, MUTEX(%rdi) +#endif +	jnz	12f + +13:	decl	READERS_QUEUED(%rdi) +	jmp	2b + +5:	xorl	%edx, %edx +	incl	NR_READERS(%rdi) +	je	8f +9:	LOCK +#if MUTEX == 0 +	decl	(%rdi) +#else +	decl	MUTEX(%rdi) +#endif +	jne	6f +7: + +	movq	%rdx, %rax +	retq + +1:	movl	PSHARED(%rdi), %esi +#if MUTEX != 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_lock_wait +#if MUTEX != 0 +	subq	$MUTEX, %rdi +#endif +	jmp	2b + +14:	cmpl	%fs:TID, %eax +	jne	3b +	/* Deadlock detected.  */ +	movl	$EDEADLK, %edx +	jmp	9b + +6:	movl	PSHARED(%rdi), %esi +#if MUTEX != 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_unlock_wake +#if MUTEX != 0 +	subq	$MUTEX, %rdi +#endif +	jmp	7b + +	/* Overflow.  */ +8:	decl	NR_READERS(%rdi) +	movl	$EAGAIN, %edx +	jmp	9b + +	/* Overflow.  */ +4:	decl	READERS_QUEUED(%rdi) +	movl	$EAGAIN, %edx +	jmp	9b + +10:	movl	PSHARED(%rdi), %esi +#if MUTEX != 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_unlock_wake +#if MUTEX != 0 +	subq	$MUTEX, %rdi +#endif +	jmp	11b + +12:	movl	PSHARED(%rdi), %esi +#if MUTEX == 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_lock_wait +#if MUTEX != 0 +	subq	$MUTEX, %rdi +#endif +	jmp	13b +	cfi_endproc +	.size	__pthread_rwlock_rdlock,.-__pthread_rwlock_rdlock + +	.globl	pthread_rwlock_rdlock +pthread_rwlock_rdlock = __pthread_rwlock_rdlock + +	.globl	__pthread_rwlock_rdlock_internal +__pthread_rwlock_rdlock_internal = __pthread_rwlock_rdlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S new file mode 100644 index 000000000..3629ffbe5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S @@ -0,0 +1,276 @@ +/* Copyright (C) 2002-2005, 2007, 2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <bits/kernel-features.h> +#include <tcb-offsets.h> + + +/* For the calculation see asm/vsyscall.h.  */ +#define VSYSCALL_ADDR_vgettimeofday	0xffffffffff600000 + +	.text + +	.globl	pthread_rwlock_timedrdlock +	.type	pthread_rwlock_timedrdlock,@function +	.align	16 +pthread_rwlock_timedrdlock: +	cfi_startproc +	pushq	%r12 +	cfi_adjust_cfa_offset(8) +	cfi_rel_offset(%r12, 0) +	pushq	%r13 +	cfi_adjust_cfa_offset(8) +	cfi_rel_offset(%r13, 0) +#ifdef __ASSUME_FUTEX_CLOCK_REALTIME +# define VALREG	%edx +#else +	pushq	%r14 +	cfi_adjust_cfa_offset(8) +	cfi_rel_offset(%r14, 0) + +	subq	$16, %rsp +	cfi_adjust_cfa_offset(16) +# define VALREG %r14d +#endif + +	movq	%rdi, %r12 +	movq	%rsi, %r13 + +	/* Get the lock.  */ +	movl	$1, %esi +	xorl	%eax, %eax +	LOCK +#if MUTEX == 0 +	cmpxchgl %esi, (%rdi) +#else +	cmpxchgl %esi, MUTEX(%rdi) +#endif +	jnz	1f + +2:	movl	WRITER(%r12), %eax +	testl	%eax, %eax +	jne	14f +	cmpl	$0, WRITERS_QUEUED(%r12) +	je	5f +	cmpl	$0, FLAGS(%r12) +	je	5f + +	/* Check the value of the timeout parameter.  */ +3:	cmpq	$1000000000, 8(%r13) +	jae	19f + +	incl	READERS_QUEUED(%r12) +	je	4f + +	movl	READERS_WAKEUP(%r12), VALREG + +	/* Unlock.  */ +	LOCK +#if MUTEX == 0 +	decl	(%r12) +#else +	decl	MUTEX(%r12) +#endif +	jne	10f + +11: +#ifndef __ASSUME_FUTEX_CLOCK_REALTIME +#  ifdef __PIC__ +	cmpl	$0, __have_futex_clock_realtime(%rip) +#  else +	cmpl	$0, __have_futex_clock_realtime +#  endif +	je	.Lreltmo +#endif + +	movl	$FUTEX_PRIVATE_FLAG|FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME, %esi +	xorl	PSHARED(%r12), %esi +	movq	%r13, %r10 +	movl	$0xffffffff, %r9d +#ifndef __ASSUME_FUTEX_CLOCK_REALTIME +	movl	%r14d, %edx +#endif +21:	leaq	READERS_WAKEUP(%r12), %rdi +	movl	$SYS_futex, %eax +	syscall +	movq	%rax, %rdx + +#ifndef __ASSUME_FUTEX_CLOCK_REALTIME +	.subsection 2 +.Lreltmo: +	/* Get current time.  */ +	movq	%rsp, %rdi +	xorl	%esi, %esi +	movq	$VSYSCALL_ADDR_vgettimeofday, %rax +	callq	*%rax + +	/* Compute relative timeout.  */ +	movq	8(%rsp), %rax +	movl	$1000, %edi +	mul	%rdi		/* Milli seconds to nano seconds.  */ +	movq	(%r13), %rcx +	movq	8(%r13), %rdi +	subq	(%rsp), %rcx +	subq	%rax, %rdi +	jns	15f +	addq	$1000000000, %rdi +	decq	%rcx +15:	testq	%rcx, %rcx +	js	16f		/* Time is already up.  */ + +	/* Futex call.  */ +	movq	%rcx, (%rsp)	/* Store relative timeout.  */ +	movq	%rdi, 8(%rsp) + +# ifdef __ASSUME_PRIVATE_FUTEX +	movl	$FUTEX_PRIVATE_FLAG|FUTEX_WAIT, %esi +	xorl	PSHARED(%r12), %esi +# else +#  if FUTEX_WAIT == 0 +	movl	PSHARED(%r12), %esi +#  else +	movl	$FUTEX_WAIT, %esi +	orl	PSHARED(%r12), %esi +#  endif +	xorl	%fs:PRIVATE_FUTEX, %esi +# endif +	movq	%rsp, %r10 +	movl	%r14d, %edx + +	jmp	21b +	.previous +#endif + +17:	/* Reget the lock.  */ +	movl	$1, %esi +	xorl	%eax, %eax +	LOCK +#if MUTEX == 0 +	cmpxchgl %esi, (%r12) +#else +	cmpxchgl %esi, MUTEX(%r12) +#endif +	jnz	12f + +13:	decl	READERS_QUEUED(%r12) +	cmpq	$-ETIMEDOUT, %rdx +	jne	2b + +18:	movl	$ETIMEDOUT, %edx +	jmp	9f + + +5:	xorl	%edx, %edx +	incl	NR_READERS(%r12) +	je	8f +9:	LOCK +#if MUTEX == 0 +	decl	(%r12) +#else +	decl	MUTEX(%r12) +#endif +	jne	6f + +7:	movq	%rdx, %rax + +#ifndef __ASSUME_FUTEX_CLOCK_REALTIME +	addq	$16, %rsp +	cfi_adjust_cfa_offset(-16) +	popq	%r14 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r14) +#endif +	popq	%r13 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r13) +	popq	%r12 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r12) +	retq + +#ifdef __ASSUME_PRIVATE_FUTEX +	cfi_adjust_cfa_offset(16) +	cfi_rel_offset(%r12, 8) +	cfi_rel_offset(%r13, 0) +#else +	cfi_adjust_cfa_offset(40) +	cfi_offset(%r12, -16) +	cfi_offset(%r13, -24) +	cfi_offset(%r14, -32) +#endif +1:	movl	PSHARED(%rdi), %esi +#if MUTEX != 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_lock_wait +	jmp	2b + +14:	cmpl	%fs:TID, %eax +	jne	3b +	movl	$EDEADLK, %edx +	jmp	9b + +6:	movl	PSHARED(%r12), %esi +#if MUTEX == 0 +	movq	%r12, %rdi +#else +	leal	MUTEX(%r12), %rdi +#endif +	callq	__lll_unlock_wake +	jmp	7b + +	/* Overflow.  */ +8:	decl	NR_READERS(%r12) +	movl	$EAGAIN, %edx +	jmp	9b + +	/* Overflow.  */ +4:	decl	READERS_QUEUED(%r12) +	movl	$EAGAIN, %edx +	jmp	9b + +10:	movl	PSHARED(%r12), %esi +#if MUTEX == 0 +	movq	%r12, %rdi +#else +	leaq	MUTEX(%r12), %rdi +#endif +	callq	__lll_unlock_wake +	jmp	11b + +12:	movl	PSHARED(%r12), %esi +#if MUTEX == 0 +	movq	%r12, %rdi +#else +	leaq	MUTEX(%r12), %rdi +#endif +	callq	__lll_lock_wait +	jmp	13b + +16:	movq	$-ETIMEDOUT, %rdx +	jmp	17b + +19:	movl	$EINVAL, %edx +	jmp	9b +	cfi_endproc +	.size	pthread_rwlock_timedrdlock,.-pthread_rwlock_timedrdlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S new file mode 100644 index 000000000..23e1ee155 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S @@ -0,0 +1,268 @@ +/* Copyright (C) 2002, 2003, 2005, 2007, 2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <bits/kernel-features.h> +#include <tcb-offsets.h> + + +/* For the calculation see asm/vsyscall.h.  */ +#define VSYSCALL_ADDR_vgettimeofday	0xffffffffff600000 + +	.text + +	.globl	pthread_rwlock_timedwrlock +	.type	pthread_rwlock_timedwrlock,@function +	.align	16 +pthread_rwlock_timedwrlock: +	cfi_startproc +	pushq	%r12 +	cfi_adjust_cfa_offset(8) +	cfi_rel_offset(%r12, 0) +	pushq	%r13 +	cfi_adjust_cfa_offset(8) +	cfi_rel_offset(%r13, 0) +#ifdef __ASSUME_FUTEX_CLOCK_REALTIME +# define VALREG	%edx +#else +	pushq	%r14 +	cfi_adjust_cfa_offset(8) +	cfi_rel_offset(%r14, 0) + +	subq	$16, %rsp +	cfi_adjust_cfa_offset(16) +# define VALREG %r14d +#endif + +	movq	%rdi, %r12 +	movq	%rsi, %r13 + +	/* Get the lock.  */ +	movl	$1, %esi +	xorl	%eax, %eax +	LOCK +#if MUTEX == 0 +	cmpxchgl %esi, (%rdi) +#else +	cmpxchgl %esi, MUTEX(%rdi) +#endif +	jnz	1f + +2:	movl	WRITER(%r12), %eax +	testl	%eax, %eax +	jne	14f +	cmpl	$0, NR_READERS(%r12) +	je	5f + +	/* Check the value of the timeout parameter.  */ +3:	cmpq	$1000000000, 8(%r13) +	jae	19f + +	incl	WRITERS_QUEUED(%r12) +	je	4f + +	movl	WRITERS_WAKEUP(%r12), VALREG + +	LOCK +#if MUTEX == 0 +	decl	(%r12) +#else +	decl	MUTEX(%r12) +#endif +	jne	10f + +11: +#ifndef __ASSUME_FUTEX_CLOCK_REALTIME +#  ifdef __PIC__ +	cmpl	$0, __have_futex_clock_realtime(%rip) +#  else +	cmpl	$0, __have_futex_clock_realtime +#  endif +	je	.Lreltmo +#endif + +	movl	$FUTEX_PRIVATE_FLAG|FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME, %esi +	xorl	PSHARED(%r12), %esi +	movq	%r13, %r10 +	movl	$0xffffffff, %r9d +#ifndef __ASSUME_FUTEX_CLOCK_REALTIME +	movl	%r14d, %edx +#endif +21:	leaq	WRITERS_WAKEUP(%r12), %rdi +	movl	$SYS_futex, %eax +	syscall +	movq	%rax, %rdx + +#ifndef __ASSUME_FUTEX_CLOCK_REALTIME +	.subsection 2 +.Lreltmo: +	/* Get current time.  */ +	movq	%rsp, %rdi +	xorl	%esi, %esi +	movq	$VSYSCALL_ADDR_vgettimeofday, %rax +	callq	*%rax + +	/* Compute relative timeout.  */ +	movq	8(%rsp), %rax +	movl	$1000, %edi +	mul	%rdi		/* Milli seconds to nano seconds.  */ +	movq	(%r13), %rcx +	movq	8(%r13), %rdi +	subq	(%rsp), %rcx +	subq	%rax, %rdi +	jns	15f +	addq	$1000000000, %rdi +	decq	%rcx +15:	testq	%rcx, %rcx +	js	16f		/* Time is already up.  */ + +	/* Futex call.  */ +	movq	%rcx, (%rsp)	/* Store relative timeout.  */ +	movq	%rdi, 8(%rsp) + +# ifdef __ASSUME_PRIVATE_FUTEX +	movl	$FUTEX_PRIVATE_FLAG|FUTEX_WAIT, %esi +	xorl	PSHARED(%r12), %esi +# else +#  if FUTEX_WAIT == 0 +	movl	PSHARED(%r12), %esi +#  else +	movl	$FUTEX_WAIT, %esi +	orl	PSHARED(%r12), %esi +#  endif +	xorl	%fs:PRIVATE_FUTEX, %esi +# endif +	movq	%rsp, %r10 +	movl	%r14d, %edx + +	jmp	21b +	.previous +#endif + +17:	/* Reget the lock.  */ +	movl	$1, %esi +	xorl	%eax, %eax +	LOCK +#if MUTEX == 0 +	cmpxchgl %esi, (%r12) +#else +	cmpxchgl %esi, MUTEX(%r12) +#endif +	jnz	12f + +13:	decl	WRITERS_QUEUED(%r12) +	cmpq	$-ETIMEDOUT, %rdx +	jne	2b + +18:	movl	$ETIMEDOUT, %edx +	jmp	9f + + +5:	xorl	%edx, %edx +	movl	%fs:TID, %eax +	movl	%eax, WRITER(%r12) +9:	LOCK +#if MUTEX == 0 +	decl	(%r12) +#else +	decl	MUTEX(%r12) +#endif +	jne	6f + +7:	movq	%rdx, %rax + +#ifndef __ASSUME_PRIVATE_FUTEX +	addq	$16, %rsp +	cfi_adjust_cfa_offset(-16) +	popq	%r14 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r14) +#endif +	popq	%r13 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r13) +	popq	%r12 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r12) +	retq + +#ifdef __ASSUME_PRIVATE_FUTEX +	cfi_adjust_cfa_offset(16) +	cfi_rel_offset(%r12, 8) +	cfi_rel_offset(%r13, 0) +#else +	cfi_adjust_cfa_offset(40) +	cfi_offset(%r12, -16) +	cfi_offset(%r13, -24) +	cfi_offset(%r14, -32) +#endif +1:	movl	PSHARED(%rdi), %esi +#if MUTEX != 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_lock_wait +	jmp	2b + +14:	cmpl	%fs:TID, %eax +	jne	3b +20:	movl	$EDEADLK, %edx +	jmp	9b + +6:	movl	PSHARED(%r12), %esi +#if MUTEX == 0 +	movq	%r12, %rdi +#else +	leal	MUTEX(%r12), %rdi +#endif +	callq	__lll_unlock_wake +	jmp	7b + +	/* Overflow.  */ +4:	decl	WRITERS_QUEUED(%r12) +	movl	$EAGAIN, %edx +	jmp	9b + +10:	movl	PSHARED(%r12), %esi +#if MUTEX == 0 +	movq	%r12, %rdi +#else +	leaq	MUTEX(%r12), %rdi +#endif +	callq	__lll_unlock_wake +	jmp	11b + +12:	movl	PSHARED(%r12), %esi +#if MUTEX == 0 +	movq	%r12, %rdi +#else +	leaq	MUTEX(%r12), %rdi +#endif +	callq	__lll_lock_wait +	jmp	13b + +16:	movq	$-ETIMEDOUT, %rdx +	jmp	17b + +19:	movl	$EINVAL, %edx +	jmp	9b +	cfi_endproc +	.size	pthread_rwlock_timedwrlock,.-pthread_rwlock_timedwrlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S new file mode 100644 index 000000000..e34c42ea2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S @@ -0,0 +1,131 @@ +/* Copyright (C) 2002, 2003, 2005, 2007, 2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelrwlock.h> +#include <bits/kernel-features.h> + + +	.text + +	.globl	__pthread_rwlock_unlock +	.type	__pthread_rwlock_unlock,@function +	.protected	__pthread_rwlock_unlock +	.align	16 +__pthread_rwlock_unlock: +	cfi_startproc +	/* Get the lock.  */ +	movl	$1, %esi +	xorl	%eax, %eax +	LOCK +#if MUTEX == 0 +	cmpxchgl %esi, (%rdi) +#else +	cmpxchgl %esi, MUTEX(%rdi) +#endif +	jnz	1f + +2:	cmpl	$0, WRITER(%rdi) +	jne	5f +	decl	NR_READERS(%rdi) +	jnz	6f + +5:	movl	$0, WRITER(%rdi) + +	movl	$1, %edx +	leaq	WRITERS_WAKEUP(%rdi), %r10 +	cmpl	$0, WRITERS_QUEUED(%rdi) +	jne	0f + +	/* If also no readers waiting nothing to do.  */ +	cmpl	$0, READERS_QUEUED(%rdi) +	je	6f + +	movl	$0x7fffffff, %edx +	leaq	READERS_WAKEUP(%rdi), %r10 + +0:	incl	(%r10) +	LOCK +#if MUTEX == 0 +	decl	(%rdi) +#else +	decl	MUTEX(%rdi) +#endif +	jne	7f + +8: +#ifdef __ASSUME_PRIVATE_FUTEX +	movl	$FUTEX_PRIVATE_FLAG|FUTEX_WAKE, %esi +	xorl	PSHARED(%rdi), %esi +#else +	movl	$FUTEX_WAKE, %esi +	orl	PSHARED(%rdi), %esi +	xorl	%fs:PRIVATE_FUTEX, %esi +#endif +	movl	$SYS_futex, %eax +	movq	%r10, %rdi +	syscall + +	xorl	%eax, %eax +	retq + +	.align	16 +6:	LOCK +#if MUTEX == 0 +	decl	(%rdi) +#else +	decl	MUTEX(%rdi) +#endif +	jne	3f + +4:	xorl	%eax, %eax +	retq + +1:	movl	PSHARED(%rdi), %esi +#if MUTEX != 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_lock_wait +#if MUTEX != 0 +	subq	$MUTEX, %rdi +#endif +	jmp	2b + +3:	movl	PSHARED(%rdi), %esi +#if MUTEX != 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_unlock_wake +	jmp	4b + +7:	movl	PSHARED(%rdi), %esi +#if MUTEX != 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_unlock_wake +	jmp	8b +	cfi_endproc +	.size	__pthread_rwlock_unlock,.-__pthread_rwlock_unlock + +	.globl	pthread_rwlock_unlock +pthread_rwlock_unlock = __pthread_rwlock_unlock + +	.globl	__pthread_rwlock_unlock_internal +__pthread_rwlock_unlock_internal = __pthread_rwlock_unlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S new file mode 100644 index 000000000..c626d9e1a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S @@ -0,0 +1,168 @@ +/* Copyright (C) 2002, 2003, 2005, 2007, 2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <bits/kernel-features.h> +#include <tcb-offsets.h> + + +	.text + +	.globl	__pthread_rwlock_wrlock +	.type	__pthread_rwlock_wrlock,@function +	.protected	__pthread_rwlock_wrlock +	.align	16 +__pthread_rwlock_wrlock: +	cfi_startproc +	xorq	%r10, %r10 + +	/* Get the lock.  */ +	movl	$1, %esi +	xorl	%eax, %eax +	LOCK +#if MUTEX == 0 +	cmpxchgl %esi, (%rdi) +#else +	cmpxchgl %esi, MUTEX(%rdi) +#endif +	jnz	1f + +2:	movl	WRITER(%rdi), %eax +	testl	%eax, %eax +	jne	14f +	cmpl	$0, NR_READERS(%rdi) +	je	5f + +3:	incl	WRITERS_QUEUED(%rdi) +	je	4f + +	movl	WRITERS_WAKEUP(%rdi), %edx + +	LOCK +#if MUTEX == 0 +	decl	(%rdi) +#else +	decl	MUTEX(%rdi) +#endif +	jne	10f + +11: +#ifdef __ASSUME_PRIVATE_FUTEX +	movl	$FUTEX_PRIVATE_FLAG|FUTEX_WAIT, %esi +	xorl	PSHARED(%rdi), %esi +#else +# if FUTEX_WAIT == 0 +	movl	PSHARED(%rdi), %esi +# else +	movl	$FUTEX_WAIT, %esi +	orl	PSHARED(%rdi), %esi +# endif +	xorl	%fs:PRIVATE_FUTEX, %esi +#endif +	addq	$WRITERS_WAKEUP, %rdi +	movl	$SYS_futex, %eax +	syscall + +	subq	$WRITERS_WAKEUP, %rdi + +	/* Reget the lock.  */ +	movl	$1, %esi +	xorl	%eax, %eax +	LOCK +#if MUTEX == 0 +	cmpxchgl %esi, (%rdi) +#else +	cmpxchgl %esi, MUTEX(%rdi) +#endif +	jnz	12f + +13:	decl	WRITERS_QUEUED(%rdi) +	jmp	2b + +5:	xorl	%edx, %edx +	movl	%fs:TID, %eax +	movl	%eax, WRITER(%rdi) +9:	LOCK +#if MUTEX == 0 +	decl	(%rdi) +#else +	decl	MUTEX(%rdi) +#endif +	jne	6f +7: + +	movq	%rdx, %rax +	retq + +1:	movl	PSHARED(%rdi), %esi +#if MUTEX != 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_lock_wait +#if MUTEX != 0 +	subq	$MUTEX, %rdi +#endif +	jmp	2b + +14:	cmpl	%fs:TID, %eax +	jne	3b +	movl	$EDEADLK, %edx +	jmp	9b + +6:	movl	PSHARED(%rdi), %esi +#if MUTEX != 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_unlock_wake +	jmp	7b + +4:	decl	WRITERS_QUEUED(%rdi) +	movl	$EAGAIN, %edx +	jmp	9b + +10:	movl	PSHARED(%rdi), %esi +#if MUTEX != 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_unlock_wake +#if MUTEX != 0 +	subq	$MUTEX, %rdi +#endif +	jmp	11b + +12:	movl	PSHARED(%rdi), %esi +#if MUTEX != 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_lock_wait +#if MUTEX != 0 +	subq	$MUTEX, %rdi +#endif +	jmp	13b +	cfi_endproc +	.size	__pthread_rwlock_wrlock,.-__pthread_rwlock_wrlock + +	.globl	pthread_rwlock_wrlock +pthread_rwlock_wrlock = __pthread_rwlock_wrlock + +	.globl	__pthread_rwlock_wrlock_internal +__pthread_rwlock_wrlock_internal = __pthread_rwlock_wrlock diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_setaffinity.c b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_setaffinity.c new file mode 100644 index 000000000..640d3044f --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_setaffinity.c @@ -0,0 +1,14 @@ +#include <tls.h> + +#define RESET_VGETCPU_CACHE() \ +  do {			      \ +    asm volatile ("movl %0, %%fs:%P1\n\t"				      \ +		  "movl %0, %%fs:%P2"					      \ +		  :							      \ +		  : "ir" (0), "i" (offsetof (struct pthread,		      \ +					     header.vgetcpu_cache[0])),	      \ +		    "i" (offsetof (struct pthread,			      \ +				   header.vgetcpu_cache[1])));		\ +  } while (0) + +#include "../pthread_setaffinity.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_spin_init.c b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_spin_init.c new file mode 100644 index 000000000..483de8cac --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_spin_init.c @@ -0,0 +1 @@ +#include <sysdeps/x86_64/pthread_spin_init.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_spin_unlock.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_spin_unlock.S new file mode 100644 index 000000000..e8e2ba262 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_spin_unlock.S @@ -0,0 +1 @@ +#include <sysdeps/x86_64/pthread_spin_unlock.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_post.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_post.S new file mode 100644 index 000000000..7af6524fe --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_post.S @@ -0,0 +1,89 @@ +/* Copyright (C) 2002, 2003, 2005, 2007, 2008 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread-errnos.h> +#include <structsem.h> + + +	.text + +	.globl	sem_post +	.type	sem_post,@function +	.align	16 +sem_post: +#if VALUE == 0 +	movl	(%rdi), %eax +#else +	movl	VALUE(%rdi), %eax +#endif +0:	cmpl	$SEM_VALUE_MAX, %eax +	je	3f +	leal	1(%rax), %esi +	LOCK +#if VALUE == 0 +	cmpxchgl %esi, (%rdi) +#else +	cmpxchgl %esi, VALUE(%rdi) +#endif +	jnz	0b + +	cmpq	$0, NWAITERS(%rdi) +	je	2f + +	movl	$SYS_futex, %eax +	movl	$FUTEX_WAKE, %esi +	orl	PRIVATE(%rdi), %esi +	movl	$1, %edx +	syscall + +	testq	%rax, %rax +	js	1f + +2:	xorl	%eax, %eax +	retq + +1: +#if USE___THREAD +	movl	$EINVAL, %eax +#else +	callq	__errno_location@plt +	movl	$EINVAL, %edx +#endif +	jmp	4f + +3: +#if USE___THREAD +	movl	$EOVERFLOW, %eax +#else +	callq	__errno_location@plt +	movl	$EOVERFLOW, %edx +#endif + +4: +#if USE___THREAD +	movq	errno@gottpoff(%rip), %rdx +	movl	%eax, %fs:(%rdx) +#else +	movl	%edx, (%rax) +#endif +	orl	$-1, %eax +	retq +	.size	sem_post,.-sem_post diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S new file mode 100644 index 000000000..704a2223a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S @@ -0,0 +1,379 @@ +/* Copyright (C) 2002, 2003, 2005, 2007, 2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <bits/kernel-features.h> +#include <lowlevellock.h> +#include <pthread-errnos.h> +#include <structsem.h> + + +/* For the calculation see asm/vsyscall.h.  */ +#define VSYSCALL_ADDR_vgettimeofday	0xffffffffff600000 + +	.text + +	.globl	sem_timedwait +	.type	sem_timedwait,@function +	.align	16 +sem_timedwait: +.LSTARTCODE: +	cfi_startproc +#if VALUE == 0 +	movl	(%rdi), %eax +#else +	movl	VALUE(%rdi), %eax +#endif +2:	testl	%eax, %eax +	je	1f + +	leaq	-1(%rax), %rdx +	LOCK +#if VALUE == 0 +	cmpxchgl %edx, (%rdi) +#else +	cmpxchgl %edx, VALUE(%rdi) +#endif +	jne	2b + +	xorl	%eax, %eax +	retq + +	/* Check whether the timeout value is valid.  */ +1:	cmpq	$1000000000, 8(%rsi) +	jae	6f + +#ifndef __ASSUME_FUTEX_CLOCK_REALTIME +#  ifdef __PIC__ +	cmpl	$0, __have_futex_clock_realtime(%rip) +#  else +	cmpl	$0, __have_futex_clock_realtime +#  endif +	je	.Lreltmo +#endif + +	/* This push is only needed to store the sem_t pointer for the +	   exception handler.  */ +	pushq	%rdi +	cfi_adjust_cfa_offset(8) + +	movq	%rsi, %r10 + +	LOCK +	addq	$1, NWAITERS(%rdi) + +.LcleanupSTART: +13:	call	__pthread_enable_asynccancel +	movl	%eax, %r8d + +#if VALUE != 0 +	leaq	VALUE(%rdi), %rdi +#endif +	movl	$0xffffffff, %r9d +	movl	$FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME, %esi +	orl	PRIVATE(%rdi), %esi +	movl	$SYS_futex, %eax +	xorl	%edx, %edx +	syscall +	movq	%rax, %r9 +#if VALUE != 0 +	leaq	-VALUE(%rdi), %rdi +#endif + +	xchgq	%r8, %rdi +	call	__pthread_disable_asynccancel +.LcleanupEND: +	movq	%r8, %rdi + +	testq	%r9, %r9 +	je	11f +	cmpq	$-EWOULDBLOCK, %r9 +	jne	3f + +11: +#if VALUE == 0 +	movl	(%rdi), %eax +#else +	movl	VALUE(%rdi), %eax +#endif +14:	testl	%eax, %eax +	je	13b + +	leaq	-1(%rax), %rcx +	LOCK +#if VALUE == 0 +	cmpxchgl %ecx, (%rdi) +#else +	cmpxchgl %ecx, VALUE(%rdi) +#endif +	jne	14b + +	xorl	%eax, %eax + +15:	LOCK +	subq	$1, NWAITERS(%rdi) + +	leaq	8(%rsp), %rsp +	cfi_adjust_cfa_offset(-8) +	retq + +	cfi_adjust_cfa_offset(8) +3:	negq	%r9 +#if USE___THREAD +	movq	errno@gottpoff(%rip), %rdx +	movl	%r9d, %fs:(%rdx) +#else +	callq	__errno_location@plt +	movl	%r9d, (%rax) +#endif + +	orl	$-1, %eax +	jmp	15b + +	cfi_adjust_cfa_offset(-8) +6: +#if USE___THREAD +	movq	errno@gottpoff(%rip), %rdx +	movl	$EINVAL, %fs:(%rdx) +#else +	callq	__errno_location@plt +	movl	$EINVAL, (%rax) +#endif + +	orl	$-1, %eax + +	retq + +#ifndef __ASSUME_FUTEX_CLOCK_REALTIME +.Lreltmo: +	pushq	%r12 +	cfi_adjust_cfa_offset(8) +	cfi_rel_offset(%r12, 0) +	pushq	%r13 +	cfi_adjust_cfa_offset(8) +	cfi_rel_offset(%r13, 0) +	pushq	%r14 +	cfi_adjust_cfa_offset(8) +	cfi_rel_offset(%r14, 0) + +#ifdef __ASSUME_FUTEX_CLOCK_REALTIME +# define STACKFRAME 8 +#else +# define STACKFRAME 24 +#endif +	subq	$STACKFRAME, %rsp +	cfi_adjust_cfa_offset(STACKFRAME) + +	movq	%rdi, %r12 +	movq	%rsi, %r13 + +	LOCK +	addq	$1, NWAITERS(%r12) + +7:	xorl	%esi, %esi +	movq	%rsp, %rdi +	movq	$VSYSCALL_ADDR_vgettimeofday, %rax +	callq	*%rax + +	/* Compute relative timeout.  */ +	movq	8(%rsp), %rax +	movl	$1000, %edi +	mul	%rdi		/* Milli seconds to nano seconds.  */ +	movq	(%r13), %rdi +	movq	8(%r13), %rsi +	subq	(%rsp), %rdi +	subq	%rax, %rsi +	jns	5f +	addq	$1000000000, %rsi +	decq	%rdi +5:	testq	%rdi, %rdi +	movl	$ETIMEDOUT, %r14d +	js	36f		/* Time is already up.  */ + +	movq	%rdi, (%rsp)	/* Store relative timeout.  */ +	movq	%rsi, 8(%rsp) + +.LcleanupSTART2: +	call	__pthread_enable_asynccancel +	movl	%eax, 16(%rsp) + +	movq	%rsp, %r10 +# if VALUE == 0 +	movq	%r12, %rdi +# else +	leaq	VALUE(%r12), %rdi +# endif +# if FUTEX_WAIT == 0 +	movl	PRIVATE(%rdi), %esi +# else +	movl	$FUTEX_WAIT, %esi +	orl	PRIVATE(%rdi), %esi +# endif +	movl	$SYS_futex, %eax +	xorl	%edx, %edx +	syscall +	movq	%rax, %r14 + +	movl	16(%rsp), %edi +	call	__pthread_disable_asynccancel +.LcleanupEND2: + +	testq	%r14, %r14 +	je	9f +	cmpq	$-EWOULDBLOCK, %r14 +	jne	33f + +9: +# if VALUE == 0 +	movl	(%r12), %eax +# else +	movl	VALUE(%r12), %eax +# endif +8:	testl	%eax, %eax +	je	7b + +	leaq	-1(%rax), %rcx +	LOCK +# if VALUE == 0 +	cmpxchgl %ecx, (%r12) +# else +	cmpxchgl %ecx, VALUE(%r12) +# endif +	jne	8b + +	xorl	%eax, %eax + +45:	LOCK +	subq	$1, NWAITERS(%r12) + +	addq	$STACKFRAME, %rsp +	cfi_adjust_cfa_offset(-STACKFRAME) +	popq	%r14 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r14) +	popq	%r13 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r13) +	popq	%r12 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(%r12) +	retq + +	cfi_adjust_cfa_offset(STACKFRAME + 3 * 8) +	cfi_rel_offset(%r12, STACKFRAME + 2 * 8) +	cfi_rel_offset(%r13, STACKFRAME + 1 * 8) +	cfi_rel_offset(%r14, STACKFRAME) +33:	negq	%r14 +36: +#if USE___THREAD +	movq	errno@gottpoff(%rip), %rdx +	movl	%r14d, %fs:(%rdx) +#else +	callq	__errno_location@plt +	movl	%r14d, (%rax) +#endif + +	orl	$-1, %eax +	jmp	45b +#endif +	cfi_endproc +	.size	sem_timedwait,.-sem_timedwait + + +	.type	sem_timedwait_cleanup,@function +sem_timedwait_cleanup: +	cfi_startproc +	cfi_adjust_cfa_offset(8) + +	movq	(%rsp), %rdi +	LOCK +	subq	$1, NWAITERS(%rdi) +	movq	%rax, %rdi +.LcallUR: +	call	_Unwind_Resume@PLT +	hlt +.LENDCODE: +	cfi_endproc +	.size	sem_timedwait_cleanup,.-sem_timedwait_cleanup + + +#ifndef __ASSUME_FUTEX_CLOCK_REALTIME +	.type	sem_timedwait_cleanup2,@function +sem_timedwait_cleanup2: +	cfi_startproc +	cfi_adjust_cfa_offset(STACKFRAME + 3 * 8) +	cfi_rel_offset(%r12, STACKFRAME + 2 * 8) +	cfi_rel_offset(%r13, STACKFRAME + 1 * 8) +	cfi_rel_offset(%r14, STACKFRAME) + +	LOCK +	subq	$1, NWAITERS(%r12) +	movq	%rax, %rdi +	movq	STACKFRAME(%rsp), %r14 +	movq	STACKFRAME+8(%rsp), %r13 +	movq	STACKFRAME+16(%rsp), %r12 +.LcallUR2: +	call	_Unwind_Resume@PLT +	hlt +.LENDCODE2: +	cfi_endproc +	.size	sem_timedwait_cleanup2,.-sem_timedwait_cleanup2 +#endif + + +	.section .gcc_except_table,"a",@progbits +.LexceptSTART: +	.byte	DW_EH_PE_omit			# @LPStart format +	.byte	DW_EH_PE_omit			# @TType format +	.byte	DW_EH_PE_uleb128		# call-site format +	.uleb128 .Lcstend-.Lcstbegin +.Lcstbegin: +	.uleb128 .LcleanupSTART-.LSTARTCODE +	.uleb128 .LcleanupEND-.LcleanupSTART +	.uleb128 sem_timedwait_cleanup-.LSTARTCODE +	.uleb128  0 +#ifndef __ASSUME_FUTEX_CLOCK_REALTIME +	.uleb128 .LcleanupSTART2-.LSTARTCODE +	.uleb128 .LcleanupEND2-.LcleanupSTART2 +	.uleb128 sem_timedwait_cleanup2-.LSTARTCODE +	.uleb128  0 +#endif +	.uleb128 .LcallUR-.LSTARTCODE +	.uleb128 .LENDCODE-.LcallUR +	.uleb128 0 +	.uleb128  0 +#ifndef __ASSUME_FUTEX_CLOCK_REALTIME +	.uleb128 .LcallUR2-.LSTARTCODE +	.uleb128 .LENDCODE2-.LcallUR2 +	.uleb128 0 +	.uleb128  0 +#endif +.Lcstend: + + +#ifdef SHARED +	.hidden	DW.ref.__gcc_personality_v0 +	.weak	DW.ref.__gcc_personality_v0 +	.section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits +	.align	8 +	.type	DW.ref.__gcc_personality_v0, @object +	.size	DW.ref.__gcc_personality_v0, 8 +DW.ref.__gcc_personality_v0: +	.quad	__gcc_personality_v0 +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_trywait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_trywait.S new file mode 100644 index 000000000..7b7f63ddb --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_trywait.S @@ -0,0 +1,52 @@ +/* Copyright (C) 2002, 2003, 2005, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread-errnos.h> + +	.text + +	.globl	sem_trywait +	.type	sem_trywait,@function +	.align	16 +sem_trywait: +	movl	(%rdi), %eax +2:	testl	%eax, %eax +	jz	1f + +	leal	-1(%rax), %edx +	LOCK +	cmpxchgl %edx, (%rdi) +	jne	2b + +	xorl	%eax, %eax +	retq + +1: +#if USE___THREAD +	movq	errno@gottpoff(%rip), %rdx +	movl	$EAGAIN, %fs:(%rdx) +#else +	callq	__errno_location@plt +	movl	$EAGAIN, (%rax) +#endif +	orl	$-1, %eax +	retq +	.size	sem_trywait,.-sem_trywait diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S new file mode 100644 index 000000000..f6b39bd74 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S @@ -0,0 +1,174 @@ +/* Copyright (C) 2002, 2003, 2005, 2007, 2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread-errnos.h> +#include <structsem.h> + + +	.text + +	.globl	sem_wait +	.type	sem_wait,@function +	.align	16 +sem_wait: +.LSTARTCODE: +	cfi_startproc + +#if VALUE == 0 +	movl	(%rdi), %eax +#else +	movl	VALUE(%rdi), %eax +#endif +2:	testl	%eax, %eax +	je	1f + +	leal	-1(%rax), %edx +	LOCK +#if VALUE == 0 +	cmpxchgl %edx, (%rdi) +#else +	cmpxchgl %edx, VALUE(%rdi) +#endif +	jne	2b + +	xorl	%eax, %eax +	retq + +	/* This push is only needed to store the sem_t pointer for the +	   exception handler.  */ +1:	pushq	%rdi +	cfi_adjust_cfa_offset(8) + +	LOCK +	addq	$1, NWAITERS(%rdi) + +.LcleanupSTART: +6:	call	__pthread_enable_asynccancel +	movl	%eax, %r8d + +	xorq	%r10, %r10 +	movl	$SYS_futex, %eax +#if FUTEX_WAIT == 0 +	movl	PRIVATE(%rdi), %esi +#else +	movl	$FUTEX_WAIT, %esi +	orl	PRIVATE(%rdi), %esi +#endif +	xorl	%edx, %edx +	syscall +	movq	%rax, %rcx + +	xchgq	%r8, %rdi +	call	__pthread_disable_asynccancel +.LcleanupEND: +	movq	%r8, %rdi + +	testq	%rcx, %rcx +	je	3f +	cmpq	$-EWOULDBLOCK, %rcx +	jne	4f + +3: +#if VALUE == 0 +	movl	(%rdi), %eax +#else +	movl	VALUE(%rdi), %eax +#endif +5:	testl	%eax, %eax +	je	6b + +	leal	-1(%rax), %edx +	LOCK +#if VALUE == 0 +	cmpxchgl %edx, (%rdi) +#else +	cmpxchgl %edx, VALUE(%rdi) +#endif +	jne	5b + +	xorl	%eax, %eax + +9:	LOCK +	subq	$1, NWAITERS(%rdi) + +	leaq	8(%rsp), %rsp +	cfi_adjust_cfa_offset(-8) + +	retq + +	cfi_adjust_cfa_offset(8) +4:	negq	%rcx +#if USE___THREAD +	movq	errno@gottpoff(%rip), %rdx +	movl	%ecx, %fs:(%rdx) +#else +# error "not supported.  %rcx and %rdi must be preserved" +	callq	__errno_location@plt +	movl	%ecx, (%rax) +#endif +	orl	$-1, %eax + +	jmp 9b +	.size	sem_wait,.-sem_wait + + +	.type	sem_wait_cleanup,@function +sem_wait_cleanup: +	movq	(%rsp), %rdi +	LOCK +	subq	$1, NWAITERS(%rdi) +	movq	%rax, %rdi +.LcallUR: +	call	_Unwind_Resume@PLT +	hlt +.LENDCODE: +	cfi_endproc +	.size	sem_wait_cleanup,.-sem_wait_cleanup + + +	.section .gcc_except_table,"a",@progbits +.LexceptSTART: +	.byte	DW_EH_PE_omit			# @LPStart format +	.byte	DW_EH_PE_omit			# @TType format +	.byte	DW_EH_PE_uleb128		# call-site format +	.uleb128 .Lcstend-.Lcstbegin +.Lcstbegin: +	.uleb128 .LcleanupSTART-.LSTARTCODE +	.uleb128 .LcleanupEND-.LcleanupSTART +	.uleb128 sem_wait_cleanup-.LSTARTCODE +	.uleb128  0 +	.uleb128 .LcallUR-.LSTARTCODE +	.uleb128 .LENDCODE-.LcallUR +	.uleb128 0 +	.uleb128  0 +.Lcstend: + + +#ifdef SHARED +	.hidden	DW.ref.__gcc_personality_v0 +	.weak	DW.ref.__gcc_personality_v0 +	.section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits +	.align	8 +	.type	DW.ref.__gcc_personality_v0, @object +	.size	DW.ref.__gcc_personality_v0, 8 +DW.ref.__gcc_personality_v0: +	.quad	__gcc_personality_v0 +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h new file mode 100644 index 000000000..1c93952d4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sysdep-cancel.h @@ -0,0 +1,111 @@ +/* Copyright (C) 2002-2006, 2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Jakub Jelinek <jakub@redhat.com>, 2002. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +/* The code to disable cancellation depends on the fact that the called +   functions are special.  They don't modify registers other than %rax +   and %r11 if they return.  Therefore we don't have to preserve other +   registers around these calls.  */ +# undef PSEUDO +# define PSEUDO(name, syscall_name, args)				      \ +  .text;								      \ +  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);					      \ +    cmpq $-4095, %rax;							      \ +    jae SYSCALL_ERROR_LABEL;						      \ +    ret;								      \ +  .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;	      \ +  L(pseudo_cancel):							      \ +    /* We always have to align the stack before calling a function.  */	      \ +    subq $8, %rsp; cfi_adjust_cfa_offset (8);				      \ +    CENABLE								      \ +    /* The return value from CENABLE is argument for CDISABLE.  */	      \ +    movq %rax, (%rsp);							      \ +    DO_CALL (syscall_name, args);					      \ +    movq (%rsp), %rdi;							      \ +    /* Save %rax since it's the error code from the syscall.  */	      \ +    movq %rax, %rdx;							      \ +    CDISABLE								      \ +    movq %rdx, %rax;							      \ +    addq $8,%rsp; cfi_adjust_cfa_offset (-8);				      \ +    cmpq $-4095, %rax;							      \ +    jae SYSCALL_ERROR_LABEL;						      \ +  L(pseudo_end): + + +# ifdef IS_IN_libpthread +#  define CENABLE	call __pthread_enable_asynccancel; +#  define CDISABLE	call __pthread_disable_asynccancel; +#  define __local_multiple_threads __pthread_multiple_threads +# elif !defined NOT_IN_libc +#  define CENABLE	call __libc_enable_asynccancel; +#  define CDISABLE	call __libc_disable_asynccancel; +#  define __local_multiple_threads __libc_multiple_threads +# elif defined IS_IN_librt +#  define CENABLE	call __librt_enable_asynccancel; +#  define CDISABLE	call __librt_disable_asynccancel; +# else +#  error Unsupported library +# endif + +# 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 cmpl $0, __local_multiple_threads(%rip) +#  endif + +# else + +#  ifndef __ASSEMBLER__ +#   define SINGLE_THREAD_P \ +  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ +				   header.multiple_threads) == 0, 1) +#  else +#   define SINGLE_THREAD_P cmpl $0, %fs:MULTIPLE_THREADS_OFFSET +#  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/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/vfork.S new file mode 100644 index 000000000..9a9912ca8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/vfork.S @@ -0,0 +1,43 @@ +/* Copyright (C) 2004 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +/* We want an #include_next, but we are the main source file. +   So, #include ourselves and in that incarnation we can use #include_next.  */ +#ifndef INCLUDED_SELF +# define INCLUDED_SELF +# include <vfork.S> +#else + +# include <tcb-offsets.h> + +# define SAVE_PID \ +	movl	%fs:PID, %esi;						      \ +	movl	$0x80000000, %ecx;					      \ +	movl	%esi, %edx;						      \ +	negl	%edx;							      \ +	cmove	%ecx, %edx;						      \ +	movl	%edx, %fs:PID + +# define RESTORE_PID \ +	testq	%rax, %rax;						      \ +	je	1f;							      \ +	movl	%esi, %fs:PID;						      \ +1: + +# include_next <vfork.S> +#endif  | 
