diff options
Diffstat (limited to 'libpthread/nptl/sysdeps')
501 files changed, 39132 insertions, 0 deletions
diff --git a/libpthread/nptl/sysdeps/alpha/Makefile b/libpthread/nptl/sysdeps/alpha/Makefile new file mode 100644 index 000000000..88c106bbb --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/Makefile @@ -0,0 +1,21 @@ +# 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. + +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif diff --git a/libpthread/nptl/sysdeps/alpha/dl-tls.h b/libpthread/nptl/sysdeps/alpha/dl-tls.h new file mode 100644 index 000000000..f81f95d75 --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/dl-tls.h @@ -0,0 +1,29 @@ +/* Thread-local storage handling in the ELF dynamic linker.  Alpha 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 Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License 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.  */ + + +/* Type used for the representation of TLS information in the GOT.  */ +typedef struct +{ +  unsigned long int ti_module; +  unsigned long int ti_offset; +} tls_index; + + +extern void *__tls_get_addr (tls_index *ti); diff --git a/libpthread/nptl/sysdeps/alpha/elf/pt-initfini.c b/libpthread/nptl/sysdeps/alpha/elf/pt-initfini.c new file mode 100644 index 000000000..ba2e419d6 --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/elf/pt-initfini.c @@ -0,0 +1,89 @@ +/* Special .init and .fini section support for Alpha.  NPTL 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.  */ + +/* 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. + +   This differs from what would be generated by the generic code in that +   we save and restore the GP within the function.  In order for linker +   relaxation to work, the value in the GP register on exit from a function +   must be valid for the function entry point.  Normally, a function is +   contained within one object file and this is not an issue, provided +   that the function reloads the gp after making any function calls. +   However, _init and _fini are constructed from pieces of many object +   files, all of which may have different GP values.  So we must reload +   the GP value from crti.o in crtn.o.  */ + +__asm__ ("						\n\ +#include \"defs.h\"					\n\ +							\n\ +/*@HEADER_ENDS*/					\n\ +							\n\ +/*@_init_PROLOG_BEGINS*/				\n\ +	.section .init, \"ax\", @progbits		\n\ +	.globl	_init					\n\ +	.type	_init,@function				\n\ +	.usepv	_init,std				\n\ +_init:							\n\ +	ldgp	$29, 0($27)				\n\ +	subq	$30, 16, $30				\n\ +	stq	$26, 0($30)				\n\ +	stq	$29, 8($30)				\n\ +	bsr	$26, __pthread_initialize_minimal_internal !samegp \n\ +	.align 3					\n\ +/*@_init_PROLOG_ENDS*/					\n\ +							\n\ +/*@_init_EPILOG_BEGINS*/				\n\ +	.section .init, \"ax\", @progbits		\n\ +	ldq	$26, 0($30)				\n\ +	ldq	$29, 8($30)				\n\ +	addq	$30, 16, $30				\n\ +	ret						\n\ +/*@_init_EPILOG_ENDS*/					\n\ +							\n\ +/*@_fini_PROLOG_BEGINS*/				\n\ +	.section .fini, \"ax\", @progbits		\n\ +	.globl	_fini					\n\ +	.type	_fini,@function				\n\ +	.usepv	_fini,std				\n\ +_fini:							\n\ +	ldgp	$29, 0($27)				\n\ +	subq	$30, 16, $30				\n\ +	stq	$26, 0($30)				\n\ +	stq	$29, 8($30)				\n\ +	.align 3					\n\ +/*@_fini_PROLOG_ENDS*/					\n\ +							\n\ +/*@_fini_EPILOG_BEGINS*/				\n\ +	.section .fini, \"ax\", @progbits		\n\ +	ldq	$26, 0($30)				\n\ +	ldq	$29, 8($30)				\n\ +	addq	$30, 16, $30				\n\ +	ret						\n\ +/*@_fini_EPILOG_ENDS*/					\n\ +							\n\ +/*@TRAILER_BEGINS*/					\n\ +"); diff --git a/libpthread/nptl/sysdeps/alpha/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/alpha/jmpbuf-unwind.h new file mode 100644 index 000000000..5cef8b1cf --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/jmpbuf-unwind.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2003, 2004 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 <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ +  _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ +  ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_SP] - (_adj)) + +/* We use the normal lobngjmp for unwinding.  */ +#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/alpha/libc-tls.c b/libpthread/nptl/sysdeps/alpha/libc-tls.c new file mode 100644 index 000000000..a3b68e928 --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/libc-tls.c @@ -0,0 +1,37 @@ +/* Thread-local storage handling in the ELF dynamic linker.  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.  */ + +#include <sysdeps/generic/libc-tls.c> +#include <dl-tls.h> + +#if USE_TLS + +/* On Alpha, linker optimizations are not required, so __tls_get_addr +   can be called even in statically linked binaries.  In this case module +   must be always 1 and PT_TLS segment exist in the binary, otherwise it +   would not link.  */ + +void * +__tls_get_addr (tls_index *ti) +{ +  dtv_t *dtv = THREAD_DTV (); +  return (char *) dtv[1].pointer.val + ti->ti_offset; +} + +#endif diff --git a/libpthread/nptl/sysdeps/alpha/pthread_spin_lock.S b/libpthread/nptl/sysdeps/alpha/pthread_spin_lock.S new file mode 100644 index 000000000..ce6cd41a4 --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/pthread_spin_lock.S @@ -0,0 +1,45 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Richard Henderson  <rth@twiddle.net>, 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.  */ + + +	.text +	.align	4 + +	.globl	pthread_spin_lock +	.ent	pthread_spin_lock +pthread_spin_lock: +	.frame	$sp, 0, $26, 0 +	.prologue 0 + +0:	ldl_l	$1, 0($16) +	lda	$2, 1 +	lda	$0, 0 +	bne	$1, 1f + +	stl_c	$2, 0($16) +	beq	$2, 1f +	mb +	ret + +1:	ldl	$1, 0($16) +	bne	$1, 1b +	unop +	br	0b + +	.end	pthread_spin_lock diff --git a/libpthread/nptl/sysdeps/alpha/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/alpha/pthread_spin_trylock.S new file mode 100644 index 000000000..0948da698 --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/pthread_spin_trylock.S @@ -0,0 +1,46 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Richard Henderson  <rth@twiddle.net>, 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 _ERRNO_H 1 +#include <bits/errno.h> + +	.text +	.align	4 + +	.globl	pthread_spin_trylock +	.ent	pthread_spin_trylock +pthread_spin_trylock: +	.frame	$sp, 0, $26, 0 +	.prologue 0 + +0:	ldl_l	$1, 0($16) +	lda	$2, 1 +	lda	$0, EBUSY +	bne	$1, 1f + +	stl_c	$2, 0($16) +	beq	$2, 2f +	mb +	lda	$0, 0 + +1:	ret +2:	br	0b + +	.end	pthread_spin_trylock diff --git a/libpthread/nptl/sysdeps/alpha/pthreaddef.h b/libpthread/nptl/sysdeps/alpha/pthreaddef.h new file mode 100644 index 000000000..26c4daf7b --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/pthreaddef.h @@ -0,0 +1,38 @@ +/* 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.  */ + +/* Default stack size.  */ +#define ARCH_STACK_DEFAULT_SIZE	(4 * 1024 * 1024) + +/* Required stack pointer alignment at beginning.  The ABI requires 16.  */ +#define STACK_ALIGN		16 + +/* Minimal stack size after allocating thread descriptor and guard size.  */ +#define MINIMAL_REST_STACK	4096 + +/* Alignment requirement for TCB.  */ +#define TCB_ALIGNMENT		16 + +/* Location of current stack frame.  */ +#define CURRENT_STACK_FRAME	__builtin_frame_address (0) + +/* XXX Until we have a better place keep the definitions here.  */ + +/* While there is no such syscall.  */ +#define __exit_thread_inline(val) \ +  INLINE_SYSCALL (exit, 1, (val)) diff --git a/libpthread/nptl/sysdeps/alpha/tcb-offsets.sym b/libpthread/nptl/sysdeps/alpha/tcb-offsets.sym new file mode 100644 index 000000000..c21a79104 --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/tcb-offsets.sym @@ -0,0 +1,14 @@ +#include <sysdep.h> +#include <tls.h> + +-- + +-- Abuse tls.h macros to derive offsets relative to the thread register. +-- # define __builtin_thread_pointer()  ((void *) 0) +-- # define thread_offsetof(mem)     ((void *) &THREAD_SELF->mem - (void *) 0) +-- Ho hum, this doesn't work in gcc4, so Know Things about THREAD_SELF +#define thread_offsetof(mem)	(long)(offsetof(struct pthread, mem) - sizeof(struct pthread)) + +MULTIPLE_THREADS_OFFSET		thread_offsetof (header.multiple_threads) +PID_OFFSET			thread_offsetof (pid) +TID_OFFSET			thread_offsetof (tid) diff --git a/libpthread/nptl/sysdeps/alpha/tls.h b/libpthread/nptl/sysdeps/alpha/tls.h new file mode 100644 index 000000000..99cd27a03 --- /dev/null +++ b/libpthread/nptl/sysdeps/alpha/tls.h @@ -0,0 +1,127 @@ +/* Definition for thread-local data handling.  NPTL/Alpha version. +   Copyright (C) 2003, 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.  */ + +#ifndef _TLS_H +#define _TLS_H	1 + +#ifndef __ASSEMBLER__ +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> + +/* Type for the dtv.  */ +typedef union dtv +{ +  size_t counter; +  struct +  { +    void *val; +    bool is_static; +  } pointer; +} dtv_t; + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif /* __ASSEMBLER__ */ + + +/* We require TLS support in the tools.  */ +#ifndef HAVE_TLS_SUPPORT +# error "TLS support is required." +#endif + +/* Signal that TLS support is available.  */ +# define USE_TLS	1 + +#ifndef __ASSEMBLER__ + +/* Get system call information.  */ +# include <sysdep.h> + +/* The TP points to the start of the thread blocks.  */ +# define TLS_DTV_AT_TP	1 + +/* Get the thread descriptor definition.  */ +# include <nptl/descr.h> + +typedef struct +{ +  dtv_t *dtv; +  void *private; +} tcbhead_t; + +/* This is the size of the initial TCB.  */ +# define TLS_INIT_TCB_SIZE	sizeof (tcbhead_t) + +/* Alignment requirements for the initial TCB.  */ +# define TLS_INIT_TCB_ALIGN	16 + +/* This is the size of the TCB.  */ +# define TLS_TCB_SIZE		sizeof (tcbhead_t) + +/* This is the size we need before TCB.  */ +# define TLS_PRE_TCB_SIZE	sizeof (struct pthread) + +/* Alignment requirements for the TCB.  */ +# define TLS_TCB_ALIGN		16 + +/* Install the dtv pointer.  The pointer passed is to the element with +   index -1 which contain the length.  */ +# define INSTALL_DTV(tcbp, dtvp) \ +  (((tcbhead_t *) (tcbp))->dtv = (dtvp) + 1) + +/* Install new dtv for current thread.  */ +# define INSTALL_NEW_DTV(dtv) \ +  (THREAD_DTV() = (dtv)) + +/* Return dtv of given thread descriptor.  */ +# define GET_DTV(tcbp) \ +  (((tcbhead_t *) (tcbp))->dtv) + +/* Code to initially initialize the thread pointer.  This might need +   special attention since 'errno' is not yet available and if the +   operation can cause a failure 'errno' must not be touched.  */ +# define TLS_INIT_TP(tcbp, secondcall) \ +  (__builtin_set_thread_pointer ((void *)(tcbp)), NULL) + +/* Return the address of the dtv for the current thread.  */ +# define THREAD_DTV() \ +  (((tcbhead_t *) __builtin_thread_pointer ())->dtv) + +/* Return the thread descriptor for the current thread.  */ +# define THREAD_SELF \ + ((struct pthread *)__builtin_thread_pointer () - 1) + +/* Magic for libthread_db to know how to do THREAD_SELF.  */ +# define DB_THREAD_SELF \ +  REGISTER (64, 64, 32 * 8, -sizeof (struct pthread)) + +/* Access to data in the thread descriptor is easy.  */ +#define THREAD_GETMEM(descr, member) \ +  descr->member +#define THREAD_GETMEM_NC(descr, member, idx) \ +  descr->member[idx] +#define THREAD_SETMEM(descr, member, value) \ +  descr->member = (value) +#define THREAD_SETMEM_NC(descr, member, idx, value) \ +  descr->member[idx] = (value) + +#endif /* __ASSEMBLER__ */ + +#endif	/* tls.h */ diff --git a/libpthread/nptl/sysdeps/arm/Makefile.arch b/libpthread/nptl/sysdeps/arm/Makefile.arch new file mode 100644 index 000000000..6d16ae3fd --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/Makefile.arch @@ -0,0 +1,69 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# Portions Copyright (C) 2006 CodeSourcery +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_SSRC = pthread_spin_lock.S pthread_spin_trylock.S aeabi_read_tp.S \ +	thumb_atomics.S +libpthread_CSRC = aeabi_unwind_cpp_pr1.c + +librt_SSRC = aeabi_read_tp.S thumb_atomics.S +librt_CSRC = aeabi_unwind_cpp_pr1.c + +libc_a_CSRC = + +CFLAGS-pt-raise.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +ASFLAGS-pthread_spin_lock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +ASFLAGS-pthread_spin_trylock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +ASFLAGS-aeabi_read_tp.S = -DNOT_IN_libc=1 + +CFLAGS-arm = $(SSP_ALL_CFLAGS) + +PTHREAD_ARCH_DIR := $(top_srcdir)libpthread/nptl/sysdeps/arm +PTHREAD_ARCH_OUT := $(top_builddir)libpthread/nptl/sysdeps/arm +PTHREAD_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_SSRC)) +PTHREAD_ARCH_OBJ += $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_CSRC)) +LIBRT_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(librt_SSRC)) +LIBRT_ARCH_OBJ += $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(librt_CSRC)) + + +ifeq ($(DOPIC),y) +libpthread-a-y += $(PTHREAD_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(PTHREAD_ARCH_OBJ) +endif +libpthread-so-y += $(PTHREAD_ARCH_OBJ:.o=.oS) + +librt-a-y += $(LIBRT_ARCH_OBJ) +librt-so-y += $(LIBRT_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y += $(PTHREAD_ARCH_OBJ) + +objclean-y += nptl_arch_objclean +headers_clean-y += nptl_arch_headers_clean + +# +# Create 'tcb-offsets.h' header file. +# +CFLAGS-tcb-offsets.c = -S + +$(PTHREAD_ARCH_OUT)/tcb-offsets.c: $(PTHREAD_ARCH_DIR)/tcb-offsets.sym +	$(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_ARCH_OUT)/tcb-offsets.s: $(PTHREAD_ARCH_OUT)/tcb-offsets.c +	$(compile.c) + +nptl_arch_headers: $(PTHREAD_ARCH_OUT)/tcb-offsets.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_ARCH_OUT)/tcb-offsets.h + +nptl_arch_headers_clean: +	$(RM) $(PTHREAD_ARCH_OUT)/tcb-offsets.c		\ +	      $(PTHREAD_ARCH_OUT)/tcb-offsets.s		\ +	      $(PTHREAD_ARCH_OUT)/tcb-offsets.h + +nptl_arch_objclean: +	$(RM) $(PTHREAD_ARCH_OUT)/*.{o,os,oS} diff --git a/libpthread/nptl/sysdeps/arm/aeabi_read_tp.S b/libpthread/nptl/sysdeps/arm/aeabi_read_tp.S new file mode 100644 index 000000000..af640d625 --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/aeabi_read_tp.S @@ -0,0 +1 @@ +#include <../../../../ldso/ldso/arm/aeabi_read_tp.S> diff --git a/libpthread/nptl/sysdeps/arm/aeabi_unwind_cpp_pr1.c b/libpthread/nptl/sysdeps/arm/aeabi_unwind_cpp_pr1.c new file mode 100644 index 000000000..84683627b --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/aeabi_unwind_cpp_pr1.c @@ -0,0 +1 @@ +#include <../../../../libc/sysdeps/linux/arm/aeabi_unwind_cpp_pr1.c> diff --git a/libpthread/nptl/sysdeps/arm/dl-tls.h b/libpthread/nptl/sysdeps/arm/dl-tls.h new file mode 100644 index 000000000..e0324a7b6 --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/dl-tls.h @@ -0,0 +1,29 @@ +/* Thread-local storage handling in the ELF dynamic linker.  ARM version. +   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.  */ + + +/* Type used for the representation of TLS information in the GOT.  */ +typedef struct +{ +  unsigned long int ti_module; +  unsigned long int ti_offset; +} tls_index; + + +extern void *__tls_get_addr (tls_index *ti); diff --git a/libpthread/nptl/sysdeps/arm/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/arm/jmpbuf-unwind.h new file mode 100644 index 000000000..6e8f01d10 --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/jmpbuf-unwind.h @@ -0,0 +1,36 @@ +/* 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.  */ + +#include <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +/* Test if longjmp to JMPBUF would unwind the frame +   containing a local variable at ADDRESS.  */ +#undef _JMPBUF_UNWINDS +#define _JMPBUF_UNWINDS(jmpbuf, address, demangle) \ +  ((void *) (address) < (void *) demangle (jmpbuf[__JMP_BUF_SP])) + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ +  _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ +  ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[__JMP_BUF_SP] - (_adj)) + +/* We use the normal longjmp for unwinding.  */ +#define __libc_unwind_longjmp(buf, val) longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/arm/pthread_spin_lock.S b/libpthread/nptl/sysdeps/arm/pthread_spin_lock.S new file mode 100644 index 000000000..bd6adf794 --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/pthread_spin_lock.S @@ -0,0 +1,31 @@ +/* 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 <sysdep.h> + +	.text +	.align	4 + +ENTRY (pthread_spin_lock) +	mov	r1, #1 +1:	swp	r2, r1, [r0] +	teq	r2, #0 +	bne	1b +	mov	r0, #0 +	PSEUDO_RET_NOERRNO +END (pthread_spin_lock) diff --git a/libpthread/nptl/sysdeps/arm/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/arm/pthread_spin_trylock.S new file mode 100644 index 000000000..85931507a --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/pthread_spin_trylock.S @@ -0,0 +1,34 @@ +/* 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.  */ + +#define _ERRNO_H 1 +#include <bits/errno.h> + +#include <sysdep.h> + +	.text +	.align	4 + +ENTRY (pthread_spin_trylock) +	mov	r1, #1 +	swp	r2, r1, [r0] +	teq	r2, #0 +	moveq	r0, #0 +	movne	r0, #EBUSY +	PSEUDO_RET_NOERRNO +END (pthread_spin_trylock) diff --git a/libpthread/nptl/sysdeps/arm/pthreaddef.h b/libpthread/nptl/sysdeps/arm/pthreaddef.h new file mode 100644 index 000000000..783828a40 --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/pthreaddef.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2002, 2003, 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.  */ + +/* Default stack size.  */ +#define ARCH_STACK_DEFAULT_SIZE	(2 * 1024 * 1024) + +/* Required stack pointer alignment at beginning.  SSE requires 16 +   bytes.  */ +#define STACK_ALIGN		16 + +/* Minimal stack size after allocating thread descriptor and guard size.  */ +#define MINIMAL_REST_STACK	2048 + +/* Alignment requirement for TCB.  */ +#define TCB_ALIGNMENT		16 + + +/* Location of current stack frame.  */ +#define CURRENT_STACK_FRAME	__builtin_frame_address (0) + + +/* XXX Until we have a better place keep the definitions here.  */ +#define __exit_thread_inline(val) \ +  INLINE_SYSCALL (exit, 1, (val)) diff --git a/libpthread/nptl/sysdeps/arm/sysdep.h b/libpthread/nptl/sysdeps/arm/sysdep.h new file mode 100644 index 000000000..19bd3c3f7 --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/sysdep.h @@ -0,0 +1,91 @@ +/* Assembler macros for ARM. +   Copyright (C) 1997, 1998, 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 <sysdeps/generic/sysdep.h> + +#ifdef	__ASSEMBLER__ + +/* Syntactic details of assembler.  */ + +#define ALIGNARG(log2) log2 +/* For ELF we need the `.type' directive to make shared libs work right.  */ +#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,%##typearg; +#define ASM_SIZE_DIRECTIVE(name) .size name,.-name + +/* In ELF C symbols are asm symbols.  */ +#undef	NO_UNDERSCORES +#define NO_UNDERSCORES + +#define PLTJMP(_x)	_x##(PLT) + +/* APCS-32 doesn't preserve the condition codes across function call. */ +#ifdef __APCS_32__ +#define LOADREGS(cond, base, reglist...)\ +	ldm##cond	base,reglist +#ifdef __USE_BX__ +#define RETINSTR(cond, reg)	\ +	bx##cond	reg +#define DO_RET(_reg)		\ +	bx _reg +#else +#define RETINSTR(cond, reg)	\ +	mov##cond	pc, reg +#define DO_RET(_reg)		\ +	mov pc, _reg +#endif +#else  /* APCS-26 */ +#define LOADREGS(cond, base, reglist...)\ +	ldm##cond	base,reglist^ +#define RETINSTR(cond, reg)	\ +	mov##cond##s	pc, reg +#define DO_RET(_reg)		\ +	movs pc, _reg +#endif + +/* Define an entry point visible from C.  */ +#define	ENTRY(name)							      \ +  ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name);				      \ +  ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),function)			      \ +  .align ALIGNARG(4);							      \ +  name##:                                                                     \ +  CALL_MCOUNT + +#undef	END +#define END(name)							      \ +  ASM_SIZE_DIRECTIVE(name) + +/* If compiled for profiling, call `mcount' at the start of each function.  */ +#ifdef	PROF +#define CALL_MCOUNT			\ +	str	lr,[sp, #-4]!	;	\ +	bl	PLTJMP(mcount)	;	\ +	ldr	lr, [sp], #4	; +#else +#define CALL_MCOUNT		/* Do nothing.  */ +#endif + +#ifdef	NO_UNDERSCORES +/* Since C identifiers are not normally prefixed with an underscore +   on this system, the asm identifier `syscall_error' intrudes on the +   C name space.  Make sure we use an innocuous name.  */ +#define	syscall_error	__syscall_error +#define mcount		_mcount +#endif + +#endif	/* __ASSEMBLER__ */ diff --git a/libpthread/nptl/sysdeps/arm/tcb-offsets.sym b/libpthread/nptl/sysdeps/arm/tcb-offsets.sym new file mode 100644 index 000000000..92cc441d3 --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/tcb-offsets.sym @@ -0,0 +1,11 @@ +#include <sysdep.h> +#include <tls.h> + +-- + +-- Derive offsets relative to the thread register. +#define thread_offsetof(mem)	(long)(offsetof(struct pthread, mem) - sizeof(struct pthread)) + +MULTIPLE_THREADS_OFFSET		thread_offsetof (header.multiple_threads) +PID_OFFSET			thread_offsetof (pid) +TID_OFFSET			thread_offsetof (tid) diff --git a/libpthread/nptl/sysdeps/arm/thumb_atomics.S b/libpthread/nptl/sysdeps/arm/thumb_atomics.S new file mode 100644 index 000000000..aaa7a3d8f --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/thumb_atomics.S @@ -0,0 +1 @@ +#include <../../../../ldso/ldso/arm/thumb_atomics.S> diff --git a/libpthread/nptl/sysdeps/arm/tls.h b/libpthread/nptl/sysdeps/arm/tls.h new file mode 100644 index 000000000..b8efd59b3 --- /dev/null +++ b/libpthread/nptl/sysdeps/arm/tls.h @@ -0,0 +1,140 @@ +/* Definition for thread-local data handling.  NPTL/ARM version. +   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.  */ + +#ifndef _TLS_H +#define _TLS_H	1 + +#ifndef __ASSEMBLER__ +#include <dl-sysdep.h> + +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> + +/* Type for the dtv.  */ +typedef union dtv +{ +  size_t counter; +  struct +  { +    void *val; +    bool is_static; +  } pointer; +} dtv_t; + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif /* __ASSEMBLER__ */ + + +/* We require TLS support in the tools.  */ +#define HAVE_TLS_SUPPORT                1 +#define HAVE_TLS_MODEL_ATTRIBUTE        1 +#define HAVE___THREAD                   1 + +/* Signal that TLS support is available.  */ +#define USE_TLS	1 + +/* Like all other modern NPTL ports, ARM uses forced unwinding.  */ +#define HAVE_FORCED_UNWIND + +#ifndef __ASSEMBLER__ + +/* Get system call information.  */ +# include <sysdep.h> + +/* The TP points to the start of the thread blocks.  */ +# define TLS_DTV_AT_TP	1 + +/* Get the thread descriptor definition.  */ +# include <../../descr.h> + +typedef struct +{ +  dtv_t *dtv; +  void *private; +} tcbhead_t; + +/* This is the size of the initial TCB.  */ +# define TLS_INIT_TCB_SIZE	sizeof (tcbhead_t) + +/* Alignment requirements for the initial TCB.  */ +# define TLS_INIT_TCB_ALIGN	16 + +/* This is the size of the TCB.  */ +# define TLS_TCB_SIZE		sizeof (tcbhead_t) + +/* This is the size we need before TCB.  */ +# define TLS_PRE_TCB_SIZE	sizeof (struct pthread) + +/* Alignment requirements for the TCB.  */ +# define TLS_TCB_ALIGN		16 + +/* Install the dtv pointer.  The pointer passed is to the element with +   index -1 which contain the length.  */ +# define INSTALL_DTV(tcbp, dtvp) \ +  (((tcbhead_t *) (tcbp))->dtv = (dtvp) + 1) + +/* Install new dtv for current thread.  */ +# define INSTALL_NEW_DTV(dtv) \ +  (THREAD_DTV() = (dtv)) + +/* Return dtv of given thread descriptor.  */ +# define GET_DTV(tcbp) \ +  (((tcbhead_t *) (tcbp))->dtv) + +/* Code to initially initialize the thread pointer.  This might need +   special attention since 'errno' is not yet available and if the +   operation can cause a failure 'errno' must not be touched.  */ +# define TLS_INIT_TP(tcbp, secondcall) \ +  ({ INTERNAL_SYSCALL_DECL (err);					\ +     long result_var;							\ +     result_var = INTERNAL_SYSCALL_ARM (set_tls, err, 1, (tcbp));	\ +     INTERNAL_SYSCALL_ERROR_P (result_var, err)				\ +       ? "unknown error" : NULL; }) + +/* Return the address of the dtv for the current thread.  */ +# define THREAD_DTV() \ +  (((tcbhead_t *) __builtin_thread_pointer ())->dtv) + +/* Return the thread descriptor for the current thread.  */ +# define THREAD_SELF \ + ((struct pthread *)__builtin_thread_pointer () - 1) + +/* Magic for libthread_db to know how to do THREAD_SELF.  */ +# define DB_THREAD_SELF \ +  CONST_THREAD_AREA (32, sizeof (struct pthread)) + +/* Access to data in the thread descriptor is easy.  */ +#define THREAD_GETMEM(descr, member) \ +  descr->member +#define THREAD_GETMEM_NC(descr, member, idx) \ +  descr->member[idx] +#define THREAD_SETMEM(descr, member, value) \ +  descr->member = (value) +#define THREAD_SETMEM_NC(descr, member, idx, value) \ +  descr->member[idx] = (value) + +/* Initializing the thread pointer will generate a SIGILL if the syscall +   is not available.  */ +#define TLS_INIT_TP_EXPENSIVE 1 + +#endif /* __ASSEMBLER__ */ + +#endif	/* tls.h */ diff --git a/libpthread/nptl/sysdeps/generic/Makefile b/libpthread/nptl/sysdeps/generic/Makefile new file mode 100644 index 000000000..582661fde --- /dev/null +++ b/libpthread/nptl/sysdeps/generic/Makefile @@ -0,0 +1,13 @@ +# 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. +# + +top_srcdir=../../../../ +top_builddir=../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.in +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/generic/Makefile.in b/libpthread/nptl/sysdeps/generic/Makefile.in new file mode 100644 index 000000000..1079a5fd9 --- /dev/null +++ b/libpthread/nptl/sysdeps/generic/Makefile.in @@ -0,0 +1,30 @@ +# 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. +# + +# +# NOTE: Alpha and MIPS have their own versions of 'libc-tls.c' in +#       their architecture specific directory which will override +#       the one here. +# +libc_a_CSRC = dl-tls.c libc-tls.c + + +CFLAGS-generic = $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +PTHREAD_GENERIC_OUT:=$(top_builddir)libpthread/nptl/sysdeps/generic + +LIBC_GENERIC_OBJ:=$(patsubst %.c,$(PTHREAD_GENERIC_OUT)/%.o,$(libc_a_CSRC)) + +libc-static-y+=$(LIBC_GENERIC_OBJ) + +libc-nomulti-y+=$(LIBC_GENERIC_OBJ) + +objclean-y+=nptl_pthread_generic_clean + +nptl_pthread_generic_clean: +	$(do_rm) $(addprefix $(PTHREAD_GENERIC_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/generic/dl-tls.c b/libpthread/nptl/sysdeps/generic/dl-tls.c new file mode 100644 index 000000000..da6ebbddb --- /dev/null +++ b/libpthread/nptl/sysdeps/generic/dl-tls.c @@ -0,0 +1,895 @@ +/* Thread-local storage handling in the ELF dynamic linker.  Generic version. +   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 <libintl.h> +#include <signal.h> +#include <stdlib.h> +#include <sys/param.h> +#include <tls.h> +#include <dl-tls.h> +#include <ldsodefs.h> +#include <dl-elf.h> +#include <dl-hash.h> + +#include <assert.h> +#include <link.h> +#include <string.h> +#include <unistd.h> +#include <stdio.h> + +#define	_dl_malloc	malloc +#define _dl_memset	memset +#define _dl_mempcpy	mempcpy +#define _dl_dprintf	fprintf +#define _dl_debug_file	stderr +#define _dl_exit	exit + +/* Amount of excess space to allocate in the static TLS area +   to allow dynamic loading of modules defining IE-model TLS data.  */ +# define TLS_STATIC_SURPLUS	64 + DL_NNS * 100 + +/* Value used for dtv entries for which the allocation is delayed.  */ +# define TLS_DTV_UNALLOCATED	((void *) -1l) + + +/* Out-of-memory handler.  */ +# ifdef SHARED +static void +__attribute__ ((__noreturn__)) +oom (void) +{ +	do { +		_dl_dprintf (_dl_debug_file, +			"cannot allocate thread-local memory: ABORT\n"); +		_dl_exit (127); +	} while (1); +} +# endif + + +void *_dl_memalign(size_t alignment, size_t bytes) +{ +	return _dl_malloc(bytes); +} + + +/* + * We are trying to perform a static TLS relocation in MAP, but it was + * dynamically loaded.  This can only work if there is enough surplus in + * the static TLS area already allocated for each running thread.  If this + * object's TLS segment is too big to fit, we fail.  If it fits, + * we set MAP->l_tls_offset and return. + * This function intentionally does not return any value but signals error + * directly, as static TLS should be rare and code handling it should + * not be inlined as much as possible. + */ + + +void +internal_function __attribute_noinline__ +_dl_allocate_static_tls (struct link_map *map) +{ +	/* If the alignment requirements are too high fail.  */ +	if (map->l_tls_align > _dl_tls_static_align) +	{ +fail: +		_dl_dprintf(_dl_debug_file, "cannot allocate memory in static TLS block"); +		_dl_exit(30); +	} + +# if defined(TLS_TCB_AT_TP) +	size_t freebytes; +	size_t n; +	size_t blsize; + +	freebytes = _dl_tls_static_size - _dl_tls_static_used - TLS_TCB_SIZE; + +	blsize = map->l_tls_blocksize + map->l_tls_firstbyte_offset; +	if (freebytes < blsize) +		goto fail; + +	n = (freebytes - blsize) / map->l_tls_align; + +	size_t offset = _dl_tls_static_used + (freebytes - n * map->l_tls_align +		- map->l_tls_firstbyte_offset); + +	map->l_tls_offset = _dl_tls_static_used = offset; +# elif defined(TLS_DTV_AT_TP) +	size_t used; +	size_t check; + +	size_t offset = roundup (_dl_tls_static_used, map->l_tls_align); +	used = offset + map->l_tls_blocksize; +	check = used; + +	/* dl_tls_static_used includes the TCB at the beginning. */ +	if (check > _dl_tls_static_size) +		goto fail; + +	map->l_tls_offset = offset; +	_dl_tls_static_used = used; +# else +#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +# endif + +	/* +	 * If the object is not yet relocated we cannot initialize the +	 * static TLS region.  Delay it. +	 */ +	if (((struct elf_resolve *) map)->init_flag & RELOCS_DONE) +    { +#ifdef SHARED +		/* +		 * Update the slot information data for at least the generation of +		 * the DSO we are allocating data for. +		 */ +		if (__builtin_expect (THREAD_DTV()[0].counter != _dl_tls_generation, 0)) +			(void) _dl_update_slotinfo (map->l_tls_modid); +#endif +		_dl_init_static_tls (map); +	} +	else +		map->l_need_tls_init = 1; +} + +size_t +internal_function +_dl_next_tls_modid (void) +{ +  size_t result; + +  if (__builtin_expect (GL(dl_tls_dtv_gaps), false)) +    { +      size_t disp = 0; +      struct dtv_slotinfo_list *runp = GL(dl_tls_dtv_slotinfo_list); + +      /* Note that this branch will never be executed during program +	 start since there are no gaps at that time.  Therefore it +	 does not matter that the dl_tls_dtv_slotinfo is not allocated +	 yet when the function is called for the first times. + +	 NB: the offset +1 is due to the fact that DTV[0] is used +	 for something else.  */ +      result = GL(dl_tls_static_nelem) + 1; +      if (result <= GL(dl_tls_max_dtv_idx)) +	do +	  { +	    while (result - disp < runp->len) +	      { +		if (runp->slotinfo[result - disp].map == NULL) +		  break; + +		++result; +		assert (result <= GL(dl_tls_max_dtv_idx) + 1); +	      } + +	    if (result - disp < runp->len) +	      break; + +	    disp += runp->len; +	  } +	while ((runp = runp->next) != NULL); + +      if (result > GL(dl_tls_max_dtv_idx)) +	{ +	  /* The new index must indeed be exactly one higher than the +	     previous high.  */ +	  assert (result == GL(dl_tls_max_dtv_idx) + 1); +	  /* There is no gap anymore.  */ +	  GL(dl_tls_dtv_gaps) = false; + +	  goto nogaps; +	} +    } +  else +    { +      /* No gaps, allocate a new entry.  */ +    nogaps: + +      result = ++GL(dl_tls_max_dtv_idx); +    } + +  return result; +} + + +# ifdef SHARED +void +internal_function +_dl_determine_tlsoffset (void) +{ +  size_t max_align = TLS_TCB_ALIGN; +  size_t freetop = 0; +  size_t freebottom = 0; + +  /* The first element of the dtv slot info list is allocated.  */ +  assert (GL(dl_tls_dtv_slotinfo_list) != NULL); +  /* There is at this point only one element in the +     dl_tls_dtv_slotinfo_list list.  */ +  assert (GL(dl_tls_dtv_slotinfo_list)->next == NULL); + +  struct dtv_slotinfo *slotinfo = GL(dl_tls_dtv_slotinfo_list)->slotinfo; + +  /* Determining the offset of the various parts of the static TLS +     block has several dependencies.  In addition we have to work +     around bugs in some toolchains. + +     Each TLS block from the objects available at link time has a size +     and an alignment requirement.  The GNU ld computes the alignment +     requirements for the data at the positions *in the file*, though. +     I.e, it is not simply possible to allocate a block with the size +     of the TLS program header entry.  The data is layed out assuming +     that the first byte of the TLS block fulfills + +       p_vaddr mod p_align == &TLS_BLOCK mod p_align + +     This means we have to add artificial padding at the beginning of +     the TLS block.  These bytes are never used for the TLS data in +     this module but the first byte allocated must be aligned +     according to mod p_align == 0 so that the first byte of the TLS +     block is aligned according to p_vaddr mod p_align.  This is ugly +     and the linker can help by computing the offsets in the TLS block +     assuming the first byte of the TLS block is aligned according to +     p_align. + +     The extra space which might be allocated before the first byte of +     the TLS block need not go unused.  The code below tries to use +     that memory for the next TLS block.  This can work if the total +     memory requirement for the next TLS block is smaller than the +     gap.  */ + +# if defined(TLS_TCB_AT_TP) +  /* We simply start with zero.  */ +  size_t offset = 0; + +  for (size_t cnt = 0; slotinfo[cnt].map != NULL; ++cnt) +    { +      assert (cnt < GL(dl_tls_dtv_slotinfo_list)->len); + +      size_t firstbyte = (-slotinfo[cnt].map->l_tls_firstbyte_offset +			  & (slotinfo[cnt].map->l_tls_align - 1)); +      size_t off; +      max_align = MAX (max_align, slotinfo[cnt].map->l_tls_align); + +      if (freebottom - freetop >= slotinfo[cnt].map->l_tls_blocksize) +	{ +	  off = roundup (freetop + slotinfo[cnt].map->l_tls_blocksize +			 - firstbyte, slotinfo[cnt].map->l_tls_align) +		+ firstbyte; +	  if (off <= freebottom) +	    { +	      freetop = off; + +	      /* XXX For some architectures we perhaps should store the +		 negative offset.  */ +	      slotinfo[cnt].map->l_tls_offset = off; +	      continue; +	    } +	} + +      off = roundup (offset + slotinfo[cnt].map->l_tls_blocksize - firstbyte, +		     slotinfo[cnt].map->l_tls_align) + firstbyte; +      if (off > offset + slotinfo[cnt].map->l_tls_blocksize +		+ (freebottom - freetop)) +	{ +	  freetop = offset; +	  freebottom = off - slotinfo[cnt].map->l_tls_blocksize; +	} +      offset = off; + +      /* XXX For some architectures we perhaps should store the +	 negative offset.  */ +      slotinfo[cnt].map->l_tls_offset = off; +    } + +  GL(dl_tls_static_used) = offset; +  GL(dl_tls_static_size) = (roundup (offset + TLS_STATIC_SURPLUS, max_align) +			    + TLS_TCB_SIZE); +# elif defined(TLS_DTV_AT_TP) +  /* The TLS blocks start right after the TCB.  */ +  size_t offset = TLS_TCB_SIZE; +  size_t cnt; + +  for (cnt = 0; slotinfo[cnt].map != NULL; ++cnt) +    { +      assert (cnt < GL(dl_tls_dtv_slotinfo_list)->len); + +      size_t firstbyte = (-slotinfo[cnt].map->l_tls_firstbyte_offset +			  & (slotinfo[cnt].map->l_tls_align - 1)); +      size_t off; +      max_align = MAX (max_align, slotinfo[cnt].map->l_tls_align); + +      if (slotinfo[cnt].map->l_tls_blocksize <= freetop - freebottom) +	{ +	  off = roundup (freebottom, slotinfo[cnt].map->l_tls_align); +	  if (off - freebottom < firstbyte) +	    off += slotinfo[cnt].map->l_tls_align; +	  if (off + slotinfo[cnt].map->l_tls_blocksize - firstbyte <= freetop) +	    { +	      slotinfo[cnt].map->l_tls_offset = off - firstbyte; +	      freebottom = (off + slotinfo[cnt].map->l_tls_blocksize +			    - firstbyte); +	      continue; +	    } +	} + +      off = roundup (offset, slotinfo[cnt].map->l_tls_align); +      if (off - offset < firstbyte) +	off += slotinfo[cnt].map->l_tls_align; + +      slotinfo[cnt].map->l_tls_offset = off - firstbyte; +      if (off - firstbyte - offset > freetop - freebottom) +	{ +	  freebottom = offset; +	  freetop = off - firstbyte; +	} + +      offset = off + slotinfo[cnt].map->l_tls_blocksize - firstbyte; +    } + +  GL(dl_tls_static_used) = offset; +  GL(dl_tls_static_size) = roundup (offset + TLS_STATIC_SURPLUS, +				    TLS_TCB_ALIGN); +# else +#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +# endif + +  /* The alignment requirement for the static TLS block.  */ +  GL(dl_tls_static_align) = max_align; +} + + +/* This is called only when the data structure setup was skipped at startup, +   when there was no need for it then.  Now we have dynamically loaded +   something needing TLS, or libpthread needs it.  */ +int +internal_function +_dl_tls_setup (void) +{ +  assert (GL(dl_tls_dtv_slotinfo_list) == NULL); +  assert (GL(dl_tls_max_dtv_idx) == 0); + +  const size_t nelem = 2 + TLS_SLOTINFO_SURPLUS; + +  GL(dl_tls_dtv_slotinfo_list) +    = calloc (1, (sizeof (struct dtv_slotinfo_list) +		  + nelem * sizeof (struct dtv_slotinfo))); +  if (GL(dl_tls_dtv_slotinfo_list) == NULL) +    return -1; + +  GL(dl_tls_dtv_slotinfo_list)->len = nelem; + +  /* Number of elements in the static TLS block.  It can't be zero +     because of various assumptions.  The one element is null.  */ +  GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx) = 1; + +  /* This initializes more variables for us.  */ +  _dl_determine_tlsoffset (); + +  return 0; +} +# endif + +static void * +internal_function +allocate_dtv (void *result) +{ +  dtv_t *dtv; +  size_t dtv_length; + +  /* We allocate a few more elements in the dtv than are needed for the +     initial set of modules.  This should avoid in most cases expansions +     of the dtv.  */ +  dtv_length = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS; +  dtv = calloc (dtv_length + 2, sizeof (dtv_t)); +  if (dtv != NULL) +    { +      /* This is the initial length of the dtv.  */ +      dtv[0].counter = dtv_length; + +      /* The rest of the dtv (including the generation counter) is +	 Initialize with zero to indicate nothing there.  */ + +      /* Add the dtv to the thread data structures.  */ +      INSTALL_DTV (result, dtv); +    } +  else +    result = NULL; + +  return result; +} + + +/* Get size and alignment requirements of the static TLS block.  */ +void +internal_function +_dl_get_tls_static_info (size_t *sizep, size_t *alignp) +{ +  *sizep = GL(dl_tls_static_size); +  *alignp = GL(dl_tls_static_align); +} + + +void * +internal_function +_dl_allocate_tls_storage (void) +{ +  void *result; +  size_t size = GL(dl_tls_static_size); + +# if defined(TLS_DTV_AT_TP) +  /* Memory layout is: +     [ TLS_PRE_TCB_SIZE ] [ TLS_TCB_SIZE ] [ TLS blocks ] +			  ^ This should be returned.  */ +  size += (TLS_PRE_TCB_SIZE + GL(dl_tls_static_align) - 1) +	  & ~(GL(dl_tls_static_align) - 1); +# endif + +  /* Allocate a correctly aligned chunk of memory.  */ +  result = _dl_memalign (GL(dl_tls_static_align), size); +  if (__builtin_expect (result != NULL, 1)) +    { +      /* Allocate the DTV.  */ +      void *allocated = result; + +# if defined(TLS_TCB_AT_TP) +      /* The TCB follows the TLS blocks.  */ +      result = (char *) result + size - TLS_TCB_SIZE; + +      /* Clear the TCB data structure.  We can't ask the caller (i.e. +	 libpthread) to do it, because we will initialize the DTV et al.  */ +      _dl_memset (result, '\0', TLS_TCB_SIZE); +# elif defined(TLS_DTV_AT_TP) +      result = (char *) result + size - GL(dl_tls_static_size); + +      /* Clear the TCB data structure and TLS_PRE_TCB_SIZE bytes before it. +	 We can't ask the caller (i.e. libpthread) to do it, because we will +	 initialize the DTV et al.  */ +      _dl_memset ((char *) result - TLS_PRE_TCB_SIZE, '\0', +	      TLS_PRE_TCB_SIZE + TLS_TCB_SIZE); +# endif + +      result = allocate_dtv (result); +      if (result == NULL) +	free (allocated); +    } + +  return result; +} + + +void * +internal_function +_dl_allocate_tls_init (void *result) +{ +  if (result == NULL) +    /* The memory allocation failed.  */ +    return NULL; + +  dtv_t *dtv = GET_DTV (result); +  struct dtv_slotinfo_list *listp; +  size_t total = 0; +  size_t maxgen = 0; + +  /* We have to prepare the dtv for all currently loaded modules using +     TLS.  For those which are dynamically loaded we add the values +     indicating deferred allocation.  */ +  listp = GL(dl_tls_dtv_slotinfo_list); +  while (1) +    { +      size_t cnt; + +      for (cnt = total == 0 ? 1 : 0; cnt < listp->len; ++cnt) +	{ +	  struct link_map *map; +	  void *dest; + +	  /* Check for the total number of used slots.  */ +	  if (total + cnt > GL(dl_tls_max_dtv_idx)) +	    break; + +	  map = listp->slotinfo[cnt].map; +	  if (map == NULL) +	    /* Unused entry.  */ +	    continue; + +	  /* Keep track of the maximum generation number.  This might +	     not be the generation counter.  */ +	  maxgen = MAX (maxgen, listp->slotinfo[cnt].gen); + +	  if (map->l_tls_offset == NO_TLS_OFFSET) +	    { +	      /* For dynamically loaded modules we simply store +		 the value indicating deferred allocation.  */ +	      dtv[map->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED; +	      dtv[map->l_tls_modid].pointer.is_static = false; +	      continue; +	    } + +	  assert (map->l_tls_modid == cnt); +	  assert (map->l_tls_blocksize >= map->l_tls_initimage_size); +# if defined(TLS_TCB_AT_TP) +	  assert ((size_t) map->l_tls_offset >= map->l_tls_blocksize); +	  dest = (char *) result - map->l_tls_offset; +# elif defined(TLS_DTV_AT_TP) +	  dest = (char *) result + map->l_tls_offset; +# else +#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +# endif + +	  /* Copy the initialization image and clear the BSS part.  */ +	  dtv[map->l_tls_modid].pointer.val = dest; +	  dtv[map->l_tls_modid].pointer.is_static = true; +	  _dl_memset (_dl_mempcpy (dest, map->l_tls_initimage, +			     map->l_tls_initimage_size), '\0', +		  map->l_tls_blocksize - map->l_tls_initimage_size); +	} + +      total += cnt; +      if (total >= GL(dl_tls_max_dtv_idx)) +	break; + +      listp = listp->next; +      assert (listp != NULL); +    } + +  /* The DTV version is up-to-date now.  */ +  dtv[0].counter = maxgen; + +  return result; +} + +void * +internal_function +_dl_allocate_tls (void *mem) +{ +  return _dl_allocate_tls_init (mem == NULL +				? _dl_allocate_tls_storage () +				: allocate_dtv (mem)); +} + + +void +internal_function +_dl_deallocate_tls (void *tcb, bool dealloc_tcb) +{ +  dtv_t *dtv = GET_DTV (tcb); +  size_t cnt; + +  /* We need to free the memory allocated for non-static TLS.  */ +  for (cnt = 0; cnt < dtv[-1].counter; ++cnt) +    if (! dtv[1 + cnt].pointer.is_static +	&& dtv[1 + cnt].pointer.val != TLS_DTV_UNALLOCATED) +      free (dtv[1 + cnt].pointer.val); + +  /* The array starts with dtv[-1].  */ +#ifdef SHARED +  if (dtv != GL(dl_initial_dtv)) +#endif +    free (dtv - 1); + +  if (dealloc_tcb) +    { +# if defined(TLS_TCB_AT_TP) +      /* The TCB follows the TLS blocks.  Back up to free the whole block.  */ +      tcb -= GL(dl_tls_static_size) - TLS_TCB_SIZE; +# elif defined(TLS_DTV_AT_TP) +      /* Back up the TLS_PRE_TCB_SIZE bytes.  */ +      tcb -= (TLS_PRE_TCB_SIZE + GL(dl_tls_static_align) - 1) +	     & ~(GL(dl_tls_static_align) - 1); +# endif +      free (tcb); +    } +} + + +# ifdef SHARED +/* The __tls_get_addr function has two basic forms which differ in the +   arguments.  The IA-64 form takes two parameters, the module ID and +   offset.  The form used, among others, on IA-32 takes a reference to +   a special structure which contain the same information.  The second +   form seems to be more often used (in the moment) so we default to +   it.  Users of the IA-64 form have to provide adequate definitions +   of the following macros.  */ +#  ifndef GET_ADDR_ARGS +#   define GET_ADDR_ARGS tls_index *ti +#  endif +#  ifndef GET_ADDR_MODULE +#   define GET_ADDR_MODULE ti->ti_module +#  endif +#  ifndef GET_ADDR_OFFSET +#   define GET_ADDR_OFFSET ti->ti_offset +#  endif + + +static void * +allocate_and_init (struct link_map *map) +{ +  void *newp; + +  newp = _dl_memalign (map->l_tls_align, map->l_tls_blocksize); +  if (newp == NULL) +    oom (); + +  /* Initialize the memory.  */ +  _dl_memset (_dl_mempcpy (newp, map->l_tls_initimage, map->l_tls_initimage_size), +	  '\0', map->l_tls_blocksize - map->l_tls_initimage_size); + +  return newp; +} + + +struct link_map * +_dl_update_slotinfo (unsigned long int req_modid) +{ +  struct link_map *the_map = NULL; +  dtv_t *dtv = THREAD_DTV (); + +  /* The global dl_tls_dtv_slotinfo array contains for each module +     index the generation counter current when the entry was created. +     This array never shrinks so that all module indices which were +     valid at some time can be used to access it.  Before the first +     use of a new module index in this function the array was extended +     appropriately.  Access also does not have to be guarded against +     modifications of the array.  It is assumed that pointer-size +     values can be read atomically even in SMP environments.  It is +     possible that other threads at the same time dynamically load +     code and therefore add to the slotinfo list.  This is a problem +     since we must not pick up any information about incomplete work. +     The solution to this is to ignore all dtv slots which were +     created after the one we are currently interested.  We know that +     dynamic loading for this module is completed and this is the last +     load operation we know finished.  */ +  unsigned long int idx = req_modid; +  struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list); + +  while (idx >= listp->len) +    { +      idx -= listp->len; +      listp = listp->next; +    } + +  if (dtv[0].counter < listp->slotinfo[idx].gen) +    { +      /* The generation counter for the slot is higher than what the +	 current dtv implements.  We have to update the whole dtv but +	 only those entries with a generation counter <= the one for +	 the entry we need.  */ +      size_t new_gen = listp->slotinfo[idx].gen; +      size_t total = 0; + +      /* We have to look through the entire dtv slotinfo list.  */ +      listp =  GL(dl_tls_dtv_slotinfo_list); +      do +	{ +	  size_t cnt; + +	  for (cnt = total == 0 ? 1 : 0; cnt < listp->len; ++cnt) +	    { +	      size_t gen = listp->slotinfo[cnt].gen; + +	      if (gen > new_gen) +		/* This is a slot for a generation younger than the +		   one we are handling now.  It might be incompletely +		   set up so ignore it.  */ +		continue; + +	      /* If the entry is older than the current dtv layout we +		 know we don't have to handle it.  */ +	      if (gen <= dtv[0].counter) +		continue; + +	      /* If there is no map this means the entry is empty.  */ +	      struct link_map *map = listp->slotinfo[cnt].map; +	      if (map == NULL) +		{ +		  /* If this modid was used at some point the memory +		     might still be allocated.  */ +		  if (! dtv[total + cnt].pointer.is_static +		      && dtv[total + cnt].pointer.val != TLS_DTV_UNALLOCATED) +		    { +		      free (dtv[total + cnt].pointer.val); +		      dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED; +		    } + +		  continue; +		} + +	      /* Check whether the current dtv array is large enough.  */ +	      size_t modid = map->l_tls_modid; +	      assert (total + cnt == modid); +	      if (dtv[-1].counter < modid) +		{ +		  /* Reallocate the dtv.  */ +		  dtv_t *newp; +		  size_t newsize = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS; +		  size_t oldsize = dtv[-1].counter; + +		  assert (map->l_tls_modid <= newsize); + +		  if (dtv == GL(dl_initial_dtv)) +		    { +		      /* This is the initial dtv that was allocated +			 during rtld startup using the dl-minimal.c +			 malloc instead of the real malloc.  We can't +			 free it, we have to abandon the old storage.  */ + +		      newp = malloc ((2 + newsize) * sizeof (dtv_t)); +		      if (newp == NULL) +			oom (); +		      _dl_memcpy (newp, &dtv[-1], oldsize * sizeof (dtv_t)); +		    } +		  else +		    { +		      newp = realloc (&dtv[-1], +				      (2 + newsize) * sizeof (dtv_t)); +		      if (newp == NULL) +			oom (); +		    } + +		  newp[0].counter = newsize; + +		  /* Clear the newly allocated part.  */ +		  _dl_memset (newp + 2 + oldsize, '\0', +			  (newsize - oldsize) * sizeof (dtv_t)); + +		  /* Point dtv to the generation counter.  */ +		  dtv = &newp[1]; + +		  /* Install this new dtv in the thread data +		     structures.  */ +		  INSTALL_NEW_DTV (dtv); +		} + +	      /* If there is currently memory allocate for this +		 dtv entry free it.  */ +	      /* XXX Ideally we will at some point create a memory +		 pool.  */ +	      if (! dtv[modid].pointer.is_static +		  && dtv[modid].pointer.val != TLS_DTV_UNALLOCATED) +		/* Note that free is called for NULL is well.  We +		   deallocate even if it is this dtv entry we are +		   supposed to load.  The reason is that we call +		   memalign and not malloc.  */ +		free (dtv[modid].pointer.val); + +	      /* This module is loaded dynamically- We defer memory +		 allocation.  */ +	      dtv[modid].pointer.is_static = false; +	      dtv[modid].pointer.val = TLS_DTV_UNALLOCATED; + +	      if (modid == req_modid) +		the_map = map; +	    } + +	  total += listp->len; +	} +      while ((listp = listp->next) != NULL); + +      /* This will be the new maximum generation counter.  */ +      dtv[0].counter = new_gen; +    } + +  return the_map; +} + + +/* The generic dynamic and local dynamic model cannot be used in +   statically linked applications.  */ +void * +__tls_get_addr (GET_ADDR_ARGS) +{ +  dtv_t *dtv = THREAD_DTV (); +  struct link_map *the_map = NULL; +  void *p; + +  if (__builtin_expect (dtv[0].counter != GL(dl_tls_generation), 0)) +    the_map = _dl_update_slotinfo (GET_ADDR_MODULE); + +  p = dtv[GET_ADDR_MODULE].pointer.val; + +  if (__builtin_expect (p == TLS_DTV_UNALLOCATED, 0)) +    { +      /* The allocation was deferred.  Do it now.  */ +      if (the_map == NULL) +	{ +	  /* Find the link map for this module.  */ +	  size_t idx = GET_ADDR_MODULE; +	  struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list); + +	  while (idx >= listp->len) +	    { +	      idx -= listp->len; +	      listp = listp->next; +	    } + +	  the_map = listp->slotinfo[idx].map; +	} + +      p = dtv[GET_ADDR_MODULE].pointer.val = allocate_and_init (the_map); +      dtv[GET_ADDR_MODULE].pointer.is_static = false; +    } + +  return (char *) p + GET_ADDR_OFFSET; +} +# endif + + + +void +_dl_add_to_slotinfo (struct link_map  *l) +{ +  /* Now that we know the object is loaded successfully add +     modules containing TLS data to the dtv info table.  We +     might have to increase its size.  */ +  struct dtv_slotinfo_list *listp; +  struct dtv_slotinfo_list *prevp; +  size_t idx = l->l_tls_modid; + +  /* Find the place in the dtv slotinfo list.  */ +  listp = GL(dl_tls_dtv_slotinfo_list); +  prevp = NULL;		/* Needed to shut up gcc.  */ +  do +    { +      /* Does it fit in the array of this list element?  */ +      if (idx < listp->len) +	break; +      idx -= listp->len; +      prevp = listp; +      listp = listp->next; +    } +  while (listp != NULL); + +  if (listp == NULL) +    { +      /* When we come here it means we have to add a new element +	 to the slotinfo list.  And the new module must be in +	 the first slot.  */ +      assert (idx == 0); + +      listp = prevp->next = (struct dtv_slotinfo_list *) +	malloc (sizeof (struct dtv_slotinfo_list) +		+ TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo)); +      if (listp == NULL) +	{ +	  /* We ran out of memory.  We will simply fail this +	     call but don't undo anything we did so far.  The +	     application will crash or be terminated anyway very +	     soon.  */ + +	  /* We have to do this since some entries in the dtv +	     slotinfo array might already point to this +	     generation.  */ +	  ++GL(dl_tls_generation); + +	  _dl_dprintf (_dl_debug_file, +			"cannot create TLS data structures: ABORT\n"); +	  _dl_exit (127); +	} + +      listp->len = TLS_SLOTINFO_SURPLUS; +      listp->next = NULL; +      _dl_memset (listp->slotinfo, '\0', +	      TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo)); +    } + +  /* Add the information into the slotinfo data structure.  */ +  listp->slotinfo[idx].map = l; +  listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1; +} diff --git a/libpthread/nptl/sysdeps/generic/dl-tls.h b/libpthread/nptl/sysdeps/generic/dl-tls.h new file mode 100644 index 000000000..7703a9752 --- /dev/null +++ b/libpthread/nptl/sysdeps/generic/dl-tls.h @@ -0,0 +1,2 @@ +/* There has to be an architecture specific version of this file.  */ +#error "architecture-specific version of <dl-tls.h> missing" diff --git a/libpthread/nptl/sysdeps/generic/libc-tls.c b/libpthread/nptl/sysdeps/generic/libc-tls.c new file mode 100644 index 000000000..b78d96483 --- /dev/null +++ b/libpthread/nptl/sysdeps/generic/libc-tls.c @@ -0,0 +1,265 @@ +/* Initialization code for TLS in statically linked application. +   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 <errno.h> +#include <ldsodefs.h> +#include <tls.h> +#include <unistd.h> +#include <stdio.h> +#include <sys/param.h> +#include <elf.h> +#include <link.h> +#include <string.h> +#include <stdlib.h> + + +#ifdef SHARED + #error makefile bug, this file is for static only +#endif + +#if USE_TLS +extern ElfW(Phdr) *_dl_phdr; +extern size_t _dl_phnum; + + +static dtv_t static_dtv[2 + TLS_SLOTINFO_SURPLUS]; + + +static struct +{ +  struct dtv_slotinfo_list si; +  /* The dtv_slotinfo_list data structure does not include the actual +     information since it is defined as an array of size zero.  We define +     here the necessary entries.  Note that it is not important whether +     there is padding or not since we will always access the information +     through the 'si' element.  */ +  struct dtv_slotinfo info[2 + TLS_SLOTINFO_SURPLUS]; +} static_slotinfo; + +/* Fake link map for the application.  */ +static struct link_map static_map; + + +/* Highest dtv index currently needed.  */ +size_t _dl_tls_max_dtv_idx; +/* Flag signalling whether there are gaps in the module ID allocation.  */ +bool _dl_tls_dtv_gaps; +/* Information about the dtv slots.  */ +struct dtv_slotinfo_list *_dl_tls_dtv_slotinfo_list; +/* Number of modules in the static TLS block.  */ +size_t _dl_tls_static_nelem; +/* Size of the static TLS block.  */ +size_t _dl_tls_static_size; +/* Size actually allocated in the static TLS block.  */ +size_t _dl_tls_static_used; +/* Alignment requirement of the static TLS block.  */ +size_t _dl_tls_static_align; + +/* Generation counter for the dtv.  */ +size_t _dl_tls_generation; + + +/* Additional definitions needed by TLS initialization.  */ +#ifdef TLS_INIT_HELPER +TLS_INIT_HELPER +#endif + +static inline void +init_slotinfo (void) +{ +  /* Create the slotinfo list.  */ +  static_slotinfo.si.len = (((char *) (&static_slotinfo + 1) +			     - (char *) &static_slotinfo.si.slotinfo[0]) +			    / sizeof static_slotinfo.si.slotinfo[0]); +  // static_slotinfo.si.next = NULL;	already zero + +  /* The slotinfo list.  Will be extended by the code doing dynamic +     linking.  */ +  GL(dl_tls_max_dtv_idx) = 1; +  GL(dl_tls_dtv_slotinfo_list) = &static_slotinfo.si; +} + +static inline void +init_static_tls (size_t memsz, size_t align) +{ +  /* That is the size of the TLS memory for this object.  The initialized +     value of _dl_tls_static_size is provided by dl-open.c to request some +     surplus that permits dynamic loading of modules with IE-model TLS.  */ +  GL(dl_tls_static_size) = roundup (memsz + GL(dl_tls_static_size), +				    TLS_TCB_ALIGN); +  GL(dl_tls_static_used) = memsz; +  /* The alignment requirement for the static TLS block.  */ +  GL(dl_tls_static_align) = align; +  /* Number of elements in the static TLS block.  */ +  GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx); +} + +void +__libc_setup_tls (size_t tcbsize, size_t tcbalign) +{ +  void *tlsblock; +  size_t memsz = 0; +  size_t filesz = 0; +  void *initimage = NULL; +  size_t align = 0; +  size_t max_align = tcbalign; +  size_t tcb_offset; +  ElfW(Phdr) *phdr; + +  /* Look through the TLS segment if there is any.  */ +  if (_dl_phdr != NULL) +    for (phdr = _dl_phdr; phdr < &_dl_phdr[_dl_phnum]; ++phdr) +      if (phdr->p_type == PT_TLS) +	{ +	  /* Remember the values we need.  */ +	  memsz = phdr->p_memsz; +	  filesz = phdr->p_filesz; +	  initimage = (void *) phdr->p_vaddr; +	  align = phdr->p_align; +	  if (phdr->p_align > max_align) +	    max_align = phdr->p_align; +	  break; +	} + +  /* We have to set up the TCB block which also (possibly) contains +     'errno'.  Therefore we avoid 'malloc' which might touch 'errno'. +     Instead we use 'sbrk' which would only uses 'errno' if it fails. +     In this case we are right away out of memory and the user gets +     what she/he deserves. + +     The initialized value of _dl_tls_static_size is provided by dl-open.c +     to request some surplus that permits dynamic loading of modules with +     IE-model TLS.  */ +# if defined(TLS_TCB_AT_TP) +  tcb_offset = roundup (memsz + GL(dl_tls_static_size), tcbalign); +  tlsblock = sbrk (tcb_offset + tcbsize + max_align); +# elif defined(TLS_DTV_AT_TP) +  tcb_offset = roundup (tcbsize, align ?: 1); +  tlsblock = sbrk (tcb_offset + memsz + max_align +		     + TLS_PRE_TCB_SIZE + GL(dl_tls_static_size)); +  tlsblock += TLS_PRE_TCB_SIZE; +# else +  /* In case a model with a different layout for the TCB and DTV +     is defined add another #elif here and in the following #ifs.  */ +#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +# endif + +  /* Align the TLS block.  */ +  tlsblock = (void *) (((uintptr_t) tlsblock + max_align - 1) +		       & ~(max_align - 1)); + +  /* Initialize the dtv.  [0] is the length, [1] the generation counter.  */ +  static_dtv[0].counter = (sizeof (static_dtv) / sizeof (static_dtv[0])) - 2; +  // static_dtv[1].counter = 0;		would be needed if not already done + +  /* Initialize the TLS block.  */ +# if defined(TLS_TCB_AT_TP) +  static_dtv[2].pointer.val = ((char *) tlsblock + tcb_offset +			       - roundup (memsz, align ?: 1)); +  static_map.l_tls_offset = roundup (memsz, align ?: 1); +# elif defined(TLS_DTV_AT_TP) +  static_dtv[2].pointer.val = (char *) tlsblock + tcb_offset; +  static_map.l_tls_offset = tcb_offset; +# else +#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +# endif +  static_dtv[2].pointer.is_static = true; +  /* sbrk gives us zero'd memory, so we don't need to clear the remainder.  */ +  memcpy (static_dtv[2].pointer.val, initimage, filesz); + +  /* Install the pointer to the dtv.  */ + +  /* Initialize the thread pointer.  */ +# if defined(TLS_TCB_AT_TP) +  INSTALL_DTV ((char *) tlsblock + tcb_offset, static_dtv); + +  const char *lossage = TLS_INIT_TP ((char *) tlsblock + tcb_offset, 0); +# elif defined(TLS_DTV_AT_TP) +  INSTALL_DTV (tlsblock, static_dtv); +  const char *lossage = (char *)TLS_INIT_TP (tlsblock, 0); +# else +#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +# endif +  if (__builtin_expect (lossage != NULL, 0)) +    abort(); + +  /* We have to create a fake link map which normally would be created +     by the dynamic linker.  It just has to have enough information to +     make the TLS routines happy.  */ +  static_map.l_tls_align = align; +  static_map.l_tls_blocksize = memsz; +  static_map.l_tls_initimage = initimage; +  static_map.l_tls_initimage_size = filesz; +  static_map.l_tls_modid = 1; + +  init_slotinfo (); +  // static_slotinfo.si.slotinfo[1].gen = 0; already zero +  static_slotinfo.si.slotinfo[1].map = &static_map; + +  memsz = roundup (memsz, align ?: 1); + +# if defined(TLS_TCB_AT_TP) +  memsz += tcbsize; +# elif defined(TLS_DTV_AT_TP) +  memsz += tcb_offset; +# endif + +  init_static_tls (memsz, MAX (TLS_TCB_ALIGN, max_align)); +} + +/* This is called only when the data structure setup was skipped at startup, +   when there was no need for it then.  Now we have dynamically loaded +   something needing TLS, or libpthread needs it.  */ +int +internal_function +_dl_tls_setup (void) +{ +  init_slotinfo (); +  init_static_tls ( +# if defined(TLS_TCB_AT_TP) +		   TLS_TCB_SIZE, +# else +		   0, +# endif +		   TLS_TCB_ALIGN); +  return 0; +} + + +/* This is the minimal initialization function used when libpthread is +   not used.  */ +void +__attribute__ ((weak)) +__pthread_initialize_minimal (void) +{ +  __libc_setup_tls (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN); +} + +#elif defined NONTLS_INIT_TP + +/* This is the minimal initialization function used when libpthread is +   not used.  */ +void +__attribute__ ((weak)) +__pthread_initialize_minimal (void) +{ +  NONTLS_INIT_TP; +} + +#endif diff --git a/libpthread/nptl/sysdeps/generic/lowlevellock.h b/libpthread/nptl/sysdeps/generic/lowlevellock.h new file mode 100644 index 000000000..7f95daada --- /dev/null +++ b/libpthread/nptl/sysdeps/generic/lowlevellock.h @@ -0,0 +1,89 @@ +/* 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 <atomic.h> + + +/* Implement generic mutex.  Basic futex syscall support is required: + +     lll_futex_wait(futex, value) - call sys_futex with FUTEX_WAIT +				    and third parameter VALUE + +     lll_futex_wake(futex, value) - call sys_futex with FUTEX_WAKE +				    and third parameter VALUE +*/ + + +/* Mutex lock counter: +   bit 31 clear means unlocked; +   bit 31 set means locked. + +   All code that looks at bit 31 first increases the 'number of +   interested threads' usage counter, which is in bits 0-30. + +   All negative mutex values indicate that the mutex is still locked.  */ + + +static inline void +__generic_mutex_lock (int *mutex) +{ +  unsigned int v; + +  /* Bit 31 was clear, we got the mutex.  (this is the fastpath).  */ +  if (atomic_bit_test_set (mutex, 31) == 0) +    return; + +  atomic_increment (mutex); + +  while (1) +    { +      if (atomic_bit_test_set (mutex, 31) == 0) +	{ +	  atomic_decrement (mutex); +	  return; +	} + +      /* We have to wait now. First make sure the futex value we are +	 monitoring is truly negative (i.e. locked). */ +      v = *mutex; +      if (v >= 0) +	continue; + +      lll_futex_wait (mutex, v); +    } +} + + +static inline void +__generic_mutex_unlock (int *mutex) +{ +  /* Adding 0x80000000 to the counter results in 0 if and only if +     there are not other interested threads - we can return (this is +     the fastpath).  */ +  if (atomic_add_zero (mutex, 0x80000000)) +    return; + +  /* There are other threads waiting for this mutex, wake one of them +     up.  */ +  lll_futex_wake (mutex, 1); +} + + +#define lll_mutex_lock(futex) __generic_mutex_lock (&(futex)) +#define lll_mutex_unlock(futex) __generic_mutex_unlock (&(futex)) diff --git a/libpthread/nptl/sysdeps/generic/sysdep.h b/libpthread/nptl/sysdeps/generic/sysdep.h new file mode 100644 index 000000000..9627b3e79 --- /dev/null +++ b/libpthread/nptl/sysdeps/generic/sysdep.h @@ -0,0 +1,137 @@ +/* Generic asm macros used on many machines. +   Copyright (C) 1991,92,93,96,98,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; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef C_LABEL + +/* Define a macro we can use to construct the asm name for a C symbol.  */ +#ifndef	__UCLIBC_UNDERSCORES__ +#ifdef	__STDC__ +#define C_LABEL(name)		name##: +#else +#define C_LABEL(name)		name/**/: +#endif +#else +#ifdef	__STDC__ +#define C_LABEL(name)		_##name##: +#else +#define C_LABEL(name)		_/**/name/**/: +#endif +#endif + +#endif + +#ifdef __ASSEMBLER__ +/* Mark the end of function named SYM.  This is used on some platforms +   to generate correct debugging information.  */ +#ifndef END +#define END(sym) +#endif + +#ifndef JUMPTARGET +#define JUMPTARGET(sym)		sym +#endif + +/* Macros to generate eh_frame unwind information.  */ +# ifdef HAVE_ASM_CFI_DIRECTIVES +#  define cfi_startproc			.cfi_startproc +#  define cfi_endproc			.cfi_endproc +#  define cfi_def_cfa(reg, off)		.cfi_def_cfa reg, off +#  define cfi_def_cfa_register(reg)	.cfi_def_cfa_register reg +#  define cfi_def_cfa_offset(off)	.cfi_def_cfa_offset off +#  define cfi_adjust_cfa_offset(off)	.cfi_adjust_cfa_offset off +#  define cfi_offset(reg, off)		.cfi_offset reg, off +#  define cfi_rel_offset(reg, off)	.cfi_rel_offset reg, off +#  define cfi_register(r1, r2)		.cfi_register r1, r2 +#  define cfi_return_column(reg)	.cfi_return_column reg +#  define cfi_restore(reg)		.cfi_restore reg +#  define cfi_same_value(reg)		.cfi_same_value reg +#  define cfi_undefined(reg)		.cfi_undefined reg +#  define cfi_remember_state		.cfi_remember_state +#  define cfi_restore_state		.cfi_restore_state +#  define cfi_window_save		.cfi_window_save +# else +#  define cfi_startproc +#  define cfi_endproc +#  define cfi_def_cfa(reg, off) +#  define cfi_def_cfa_register(reg) +#  define cfi_def_cfa_offset(off) +#  define cfi_adjust_cfa_offset(off) +#  define cfi_offset(reg, off) +#  define cfi_rel_offset(reg, off) +#  define cfi_register(r1, r2) +#  define cfi_return_column(reg) +#  define cfi_restore(reg) +#  define cfi_same_value(reg) +#  define cfi_undefined(reg) +#  define cfi_remember_state +#  define cfi_restore_state +#  define cfi_window_save +# endif + +#else /* ! ASSEMBLER */ +# ifdef HAVE_ASM_CFI_DIRECTIVES +#  define CFI_STRINGIFY(Name) CFI_STRINGIFY2 (Name) +#  define CFI_STRINGIFY2(Name) #Name +#  define CFI_STARTPROC	".cfi_startproc" +#  define CFI_ENDPROC	".cfi_endproc" +#  define CFI_DEF_CFA(reg, off)	\ +   ".cfi_def_cfa " CFI_STRINGIFY(reg) "," CFI_STRINGIFY(off) +#  define CFI_DEF_CFA_REGISTER(reg) \ +   ".cfi_def_cfa_register " CFI_STRINGIFY(reg) +#  define CFI_DEF_CFA_OFFSET(off) \ +   ".cfi_def_cfa_offset " CFI_STRINGIFY(off) +#  define CFI_ADJUST_CFA_OFFSET(off) \ +   ".cfi_adjust_cfa_offset " CFI_STRINGIFY(off) +#  define CFI_OFFSET(reg, off) \ +   ".cfi_offset " CFI_STRINGIFY(reg) "," CFI_STRINGIFY(off) +#  define CFI_REL_OFFSET(reg, off) \ +   ".cfi_rel_offset " CFI_STRINGIFY(reg) "," CFI_STRINGIFY(off) +#  define CFI_REGISTER(r1, r2) \ +   ".cfi_register " CFI_STRINGIFY(r1) "," CFI_STRINGIFY(r2) +#  define CFI_RETURN_COLUMN(reg) \ +   ".cfi_return_column " CFI_STRINGIFY(reg) +#  define CFI_RESTORE(reg) \ +   ".cfi_restore " CFI_STRINGIFY(reg) +#  define CFI_UNDEFINED(reg) \ +   ".cfi_undefined " CFI_STRINGIFY(reg) +#  define CFI_REMEMBER_STATE \ +   ".cfi_remember_state" +#  define CFI_RESTORE_STATE \ +   ".cfi_restore_state" +#  define CFI_WINDOW_SAVE \ +   ".cfi_window_save" +# else +#  define CFI_STARTPROC +#  define CFI_ENDPROC +#  define CFI_DEF_CFA(reg, off) +#  define CFI_DEF_CFA_REGISTER(reg) +#  define CFI_DEF_CFA_OFFSET(off) +#  define CFI_ADJUST_CFA_OFFSET(off) +#  define CFI_OFFSET(reg, off) +#  define CFI_REL_OFFSET(reg, off) +#  define CFI_REGISTER(r1, r2) +#  define CFI_RETURN_COLUMN(reg) +#  define CFI_RESTORE(reg) +#  define CFI_UNDEFINED(reg) +#  define CFI_REMEMBER_STATE +#  define CFI_RESTORE_STATE +#  define CFI_WINDOW_SAVE +# endif + +#endif /* __ASSEMBLER__ */ diff --git a/libpthread/nptl/sysdeps/i386/Makefile b/libpthread/nptl/sysdeps/i386/Makefile new file mode 100644 index 000000000..2f0d88f30 --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/Makefile @@ -0,0 +1,27 @@ +# Copyright (C) 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; if not, write to the Free +# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# 02111-1307 USA. + +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif + +ifeq ($(subdir),nptl) +CFLAGS-pthread_create.c += -mpreferred-stack-boundary=4 +CFLAGS-tst-align.c += -mpreferred-stack-boundary=4 +CFLAGS-tst-align2.c += -mpreferred-stack-boundary=4 +endif diff --git a/libpthread/nptl/sysdeps/i386/Makefile.arch b/libpthread/nptl/sysdeps/i386/Makefile.arch new file mode 100644 index 000000000..2b9a2dc7c --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/Makefile.arch @@ -0,0 +1,53 @@ +# 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. +# + +libpthread_CSRC = pthread_spin_lock.c +libpthread_SSRC = i486/pthread_spin_trylock.S + +CFLAGS-pthread_spin_lock.c += -D_GNU_SOURCE + +CFLAGS-i386 = $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +PTHREAD_ARCH_DIR := $(top_srcdir)libpthread/nptl/sysdeps/i386/ +PTHREAD_ARCH_OUT := $(top_builddir)libpthread/nptl/sysdeps/i386/ +PTHREAD_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_SSRC)) +PTHREAD_ARCH_OBJ += $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(PTHREAD_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(PTHREAD_ARCH_OBJ) +endif +libpthread-so-y += $(PTHREAD_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y += $(PTHREAD_ARCH_OBJ) + +objclean-y += nptl_arch_clean +headers_clean-y += nptl_arch_headers_clean + +# +# Create 'tcb-offsets.h' header file. +# +CFLAGS-tcb-offsets.c = -S + +$(PTHREAD_ARCH_OUT)/tcb-offsets.c: $(PTHREAD_ARCH_DIR)/tcb-offsets.sym +	$(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_ARCH_OUT)/tcb-offsets.s: $(PTHREAD_ARCH_OUT)/tcb-offsets.c +	$(compile.c) + +$(PTHREAD_ARCH_OUT)/tcb-offsets.h: $(PTHREAD_ARCH_OUT)/tcb-offsets.s +	@sed -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +nptl_arch_headers: $(PTHREAD_ARCH_OUT)/tcb-offsets.h + +nptl_arch_headers_clean: +	$(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/tcb-offsets., c s h) + +nptl_arch_clean: +	$(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/i386/dl-tls.h b/libpthread/nptl/sysdeps/i386/dl-tls.h new file mode 100644 index 000000000..a1707197c --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/dl-tls.h @@ -0,0 +1,60 @@ +/* Thread-local storage handling in the ELF dynamic linker.  i386 version. +   Copyright (C) 2002, 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.  */ + + +/* Type used for the representation of TLS information in the GOT.  */ +typedef struct +{ +  unsigned long int ti_module; +  unsigned long int ti_offset; +} tls_index; + + +#ifdef SHARED +/* This is the prototype for the GNU version.  */ +extern void *___tls_get_addr (tls_index *ti) +     __attribute__ ((__regparm__ (1))); +extern void *___tls_get_addr_internal (tls_index *ti) +     __attribute__ ((__regparm__ (1))) attribute_hidden; + +# ifdef IS_IN_rtld +/* The special thing about the x86 TLS ABI is that we have two +   variants of the __tls_get_addr function with different calling +   conventions.  The GNU version, which we are mostly concerned here, +   takes the parameter in a register.  The name is changed by adding +   an additional underscore at the beginning.  The Sun version uses +   the normal calling convention.  */ +void * +__tls_get_addr (tls_index *ti) +{ +  return ___tls_get_addr_internal (ti); +} + + +/* Prepare using the definition of __tls_get_addr in the generic +   version of this file.  */ +# define __tls_get_addr __attribute__ ((__regparm__ (1))) ___tls_get_addr +strong_alias (___tls_get_addr, ___tls_get_addr_internal) +#else + +/* Users should get the better interface.  */ +# define __tls_get_addr ___tls_get_addr + +# endif +#endif diff --git a/libpthread/nptl/sysdeps/i386/i486/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/i386/i486/pthread_spin_trylock.S new file mode 100644 index 000000000..e30072c3d --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/i486/pthread_spin_trylock.S @@ -0,0 +1,47 @@ +/* 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 <pthread-errnos.h> + + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +	.globl	pthread_spin_trylock +	.type	pthread_spin_trylock,@function +	.align	16 +pthread_spin_trylock: +	movl	4(%esp), %edx +	movl	$1, %eax +	xorl	%ecx, %ecx +	LOCK +	cmpxchgl %ecx, (%edx) +	movl	$EBUSY, %eax +#ifdef HAVE_CMOV +	cmovel	%ecx, %eax +#else +	jne	0f +	movl	%ecx, %eax +0: +#endif +	ret +	.size	pthread_spin_trylock,.-pthread_spin_trylock diff --git a/libpthread/nptl/sysdeps/i386/i586/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/i386/i586/pthread_spin_trylock.S new file mode 100644 index 000000000..ffe3d456b --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/i586/pthread_spin_trylock.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_spin_trylock.S" diff --git a/libpthread/nptl/sysdeps/i386/i686/Makefile b/libpthread/nptl/sysdeps/i386/i686/Makefile new file mode 100644 index 000000000..137c0a2f0 --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/i686/Makefile @@ -0,0 +1,32 @@ +# Copyright (C) 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. + +ifeq ($(subdir),nptl) +# It turns out that stack coloring is in general not good on P4s.  Some +# applications will benefit.  We will probably have a configuration option +# at some point.  Enabling coloring can be done with +# +#   -DCOLORING_INCREMENT=128 +# +# What is useful is to avoid the 64k aliasing problem which reliably +# happens if all stacks use sizes which are a multiple of 64k.  Tell +# the stack allocator to disturb this by allocation one more page if +# necessary. +CFLAGS-pthread_create.c += -DMULTI_PAGE_ALIASING=65536 +endif diff --git a/libpthread/nptl/sysdeps/i386/i686/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/i386/i686/pthread_spin_trylock.S new file mode 100644 index 000000000..a5d861f92 --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/i686/pthread_spin_trylock.S @@ -0,0 +1,21 @@ +/* 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.  */ + +#define HAVE_CMOV	1 +#include "../i486/pthread_spin_trylock.S" diff --git a/libpthread/nptl/sysdeps/i386/i686/tls.h b/libpthread/nptl/sysdeps/i386/i686/tls.h new file mode 100644 index 000000000..4025ed8d2 --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/i686/tls.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 _TLS_H + +/* Additional definitions for <tls.h> on i686 and up.  */ + + +/* Macros to load from and store into segment registers.  We can use +   the 32-bit instructions.  */ +#define TLS_GET_GS() \ +  ({ int __seg; __asm ("movl %%gs, %0" : "=q" (__seg)); __seg; }) +#define TLS_SET_GS(val) \ +  __asm ("movl %0, %%gs" :: "q" (val)) + + +/* Get the full set of definitions.  */ +#include "../tls.h" + +#endif	/* tls.h */ diff --git a/libpthread/nptl/sysdeps/i386/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/i386/jmpbuf-unwind.h new file mode 100644 index 000000000..b9528f363 --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/jmpbuf-unwind.h @@ -0,0 +1,32 @@ +/* Copyright (C) 2003, 2004 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 <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ +  _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ +  ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_SP] - (_adj)) + +/* We use the normal lobngjmp for unwinding.  */ +extern __typeof(longjmp) __libc_longjmp attribute_noreturn; +#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/i386/pthread_spin_init.c b/libpthread/nptl/sysdeps/i386/pthread_spin_init.c new file mode 100644 index 000000000..0a47981aa --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/pthread_spin_init.c @@ -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.  */ + +/* Not needed.  pthread_spin_init is an alias for pthread_spin_unlock.  */ diff --git a/libpthread/nptl/sysdeps/i386/pthread_spin_lock.c b/libpthread/nptl/sysdeps/i386/pthread_spin_lock.c new file mode 100644 index 000000000..a6b1cf403 --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/pthread_spin_lock.c @@ -0,0 +1,48 @@ +/* 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 "pthreadP.h" + +#ifndef LOCK_PREFIX +# ifdef UP +#  define LOCK_PREFIX	/* nothing */ +# else +#  define LOCK_PREFIX	"lock;" +# endif +#endif + + +int +pthread_spin_lock (pthread_spinlock_t *lock) +{ +  __asm__ ("\n" +       "1:\t" LOCK_PREFIX "decl %0\n\t" +       "jne 2f\n\t" +       ".subsection 1\n\t" +       ".align 16\n" +       "2:\trep; nop\n\t" +       "cmpl $0, %0\n\t" +       "jg 1b\n\t" +       "jmp 2b\n\t" +       ".previous" +       : "=m" (*lock) +       : "m" (*lock)); + +  return 0; +} diff --git a/libpthread/nptl/sysdeps/i386/pthread_spin_unlock.S b/libpthread/nptl/sysdeps/i386/pthread_spin_unlock.S new file mode 100644 index 000000000..d94f1e7b8 --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/pthread_spin_unlock.S @@ -0,0 +1,32 @@ +/* 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.  */ + +	.globl	pthread_spin_unlock +	.type	pthread_spin_unlock,@function +	.align	16 +pthread_spin_unlock: +	movl	4(%esp), %eax +	movl	$1, (%eax) +	xorl	%eax, %eax +	ret +	.size	pthread_spin_unlock,.-pthread_spin_unlock + +	/* The implementation of pthread_spin_init is identical.  */ +	.globl	pthread_spin_init +pthread_spin_init = pthread_spin_unlock diff --git a/libpthread/nptl/sysdeps/i386/pthreaddef.h b/libpthread/nptl/sysdeps/i386/pthreaddef.h new file mode 100644 index 000000000..81456a4fc --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/pthreaddef.h @@ -0,0 +1,48 @@ +/* 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.  */ + +/* Default stack size.  */ +#define ARCH_STACK_DEFAULT_SIZE	(2 * 1024 * 1024) + +/* Required stack pointer alignment at beginning.  SSE requires 16 +   bytes.  */ +#define STACK_ALIGN		16 + +/* Minimal stack size after allocating thread descriptor and guard size.  */ +#define MINIMAL_REST_STACK	2048 + +/* Alignment requirement for TCB.  */ +#define TCB_ALIGNMENT		16 + + +/* Location of current stack frame.  */ +#define CURRENT_STACK_FRAME	__builtin_frame_address (0) + + +/* XXX Until we have a better place keep the definitions here.  */ + +/* While there is no such syscall.  */ +#define __exit_thread_inline(val) \ +  while (1) {								      \ +    if (__builtin_constant_p (val) && (val) == 0)			      \ +      __asm__ volatile ("xorl %%ebx, %%ebx; int $0x80" :: "a" (__NR_exit));	      \ +    else								      \ +      __asm__ volatile ("movl %1, %%ebx; int $0x80"				      \ +		    :: "a" (__NR_exit), "r" (val));			      \ +  } diff --git a/libpthread/nptl/sysdeps/i386/sysdep.h b/libpthread/nptl/sysdeps/i386/sysdep.h new file mode 100644 index 000000000..e49d65759 --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/sysdep.h @@ -0,0 +1,157 @@ +/* Assembler macros for i386. +   Copyright (C) 1991-93,95,96,98,2002,2003,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 <sysdeps/generic/sysdep.h> + +#ifdef	__ASSEMBLER__ + +/* Syntactic details of assembler.  */ + +/* ELF uses byte-counts for .align, most others use log2 of count of bytes.  */ +#define ALIGNARG(log2) 1<<log2 +/* For ELF we need the `.type' directive to make shared libs work right.  */ +#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,typearg; +#define ASM_SIZE_DIRECTIVE(name) .size name,.-name; + +/* In ELF C symbols are asm symbols.  */ +#undef	NO_UNDERSCORES +#define NO_UNDERSCORES + +/* Define an entry point visible from C. + +   There is currently a bug in gdb which prevents us from specifying +   incomplete stabs information.  Fake some entries here which specify +   the current source file.  */ +#define	ENTRY(name)							      \ +  STABS_CURRENT_FILE1("")						      \ +  STABS_CURRENT_FILE(name)						      \ +  ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name);				      \ +  ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function)			      \ +  .align ALIGNARG(4);							      \ +  STABS_FUN(name)							      \ +  C_LABEL(name)								      \ +  cfi_startproc;							      \ +  CALL_MCOUNT + +#undef	END +#define END(name)							      \ +  cfi_endproc;								      \ +  ASM_SIZE_DIRECTIVE(name)						      \ +  STABS_FUN_END(name) + +#ifdef HAVE_CPP_ASM_DEBUGINFO +/* Disable that goop, because we just pass -g through to the assembler +   and it generates proper line number information directly.  */ +# define STABS_CURRENT_FILE1(name) +# define STABS_CURRENT_FILE(name) +# define STABS_FUN(name) +# define STABS_FUN_END(name) +#else +/* Remove the following two lines once the gdb bug is fixed.  */ +#define STABS_CURRENT_FILE(name)					      \ +  STABS_CURRENT_FILE1 (#name) +#define STABS_CURRENT_FILE1(name)					      \ +  1: .stabs name,100,0,0,1b; +/* Emit stabs definition lines.  We use F(0,1) and define t(0,1) as `int', +   the same way gcc does it.  */ +#define STABS_FUN(name) STABS_FUN2(name, name##:F(0,1)) +#define STABS_FUN2(name, namestr)					      \ +  .stabs "int:t(0,1)=r(0,1);-2147483648;2147483647;",128,0,0,0;		      \ +  .stabs #namestr,36,0,0,name; +#define STABS_FUN_END(name)						      \ +  1: .stabs "",36,0,0,1b-name; +#endif + +/* If compiled for profiling, call `mcount' at the start of each function.  */ +#ifdef	PROF +/* The mcount code relies on a normal frame pointer being on the stack +   to locate our caller, so push one just for its benefit.  */ +#define CALL_MCOUNT \ +  pushl %ebp; cfi_adjust_cfa_offset (4); movl %esp, %ebp; \ +  cfi_def_cfa_register (ebp); call JUMPTARGET(mcount); \ +  popl %ebp; cfi_def_cfa (esp, 4); +#else +#define CALL_MCOUNT		/* Do nothing.  */ +#endif + +#ifdef	NO_UNDERSCORES +/* Since C identifiers are not normally prefixed with an underscore +   on this system, the asm identifier `syscall_error' intrudes on the +   C name space.  Make sure we use an innocuous name.  */ +#define	syscall_error	__syscall_error +#define mcount		_mcount +#endif + +#define	PSEUDO(name, syscall_name, args)				      \ +  .globl syscall_error;							      \ +lose: SYSCALL_PIC_SETUP							      \ +  jmp JUMPTARGET(syscall_error);					      \ +  ENTRY (name)								      \ +  DO_CALL (syscall_name, args);						      \ +  jb lose + +#undef	PSEUDO_END +#define	PSEUDO_END(name)						      \ +  END (name) + +#undef JUMPTARGET +#ifdef __PIC__ +#define JUMPTARGET(name)	name##@PLT +#define SYSCALL_PIC_SETUP \ +    pushl %ebx;								      \ +    cfi_adjust_cfa_offset (4);						      \ +    call 0f;								      \ +0:  popl %ebx;								      \ +    cfi_adjust_cfa_offset (-4);						      \ +    addl $_GLOBAL_OFFSET_TABLE+[.-0b], %ebx; + + +# define SETUP_PIC_REG(reg) \ +  .ifndef __x86.get_pc_thunk.reg;					      \ +  .section .gnu.linkonce.t.__x86.get_pc_thunk.reg,"ax",@progbits;	      \ +  .globl __x86.get_pc_thunk.reg;					      \ +  .hidden __x86.get_pc_thunk.reg;					      \ +  .type __x86.get_pc_thunk.reg,@function;				      \ +__x86.get_pc_thunk.reg:						      \ +  movl (%esp), %e##reg;							      \ +  ret;									      \ +  .size __x86.get_pc_thunk.reg, . - __x86.get_pc_thunk.reg;		      \ +  .previous;								      \ +  .endif;								      \ +  call __x86.get_pc_thunk.reg + +# define LOAD_PIC_REG(reg) \ +  SETUP_PIC_REG(reg); addl $_GLOBAL_OFFSET_TABLE_, %e##reg + +#else +#define JUMPTARGET(name)	name +#define SYSCALL_PIC_SETUP	/* Nothing.  */ +#endif + +/* Local label name for asm code. */ +#ifndef L +#ifdef HAVE_ELF +#define L(name)		.L##name +#else +#define L(name)		name +#endif +#endif + +#endif	/* __ASSEMBLER__ */ diff --git a/libpthread/nptl/sysdeps/i386/tcb-offsets.sym b/libpthread/nptl/sysdeps/i386/tcb-offsets.sym new file mode 100644 index 000000000..4e0444ba3 --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/tcb-offsets.sym @@ -0,0 +1,13 @@ +#include <sysdep.h> +#include <tls.h> + +RESULT			offsetof (struct pthread, result) +TID			offsetof (struct pthread, tid) +PID			offsetof (struct pthread, pid) +CANCELHANDLING		offsetof (struct pthread, cancelhandling) +CLEANUP_JMP_BUF		offsetof (struct pthread, cleanup_jmp_buf) +MULTIPLE_THREADS_OFFSET	offsetof (tcbhead_t, multiple_threads) +SYSINFO_OFFSET		offsetof (tcbhead_t, sysinfo) +CLEANUP			offsetof (struct pthread, cleanup) +CLEANUP_PREV		offsetof (struct _pthread_cleanup_buffer, __prev) +MUTEX_FUTEX		offsetof (pthread_mutex_t, __data.__lock) diff --git a/libpthread/nptl/sysdeps/i386/tls.h b/libpthread/nptl/sysdeps/i386/tls.h new file mode 100644 index 000000000..52bde9eec --- /dev/null +++ b/libpthread/nptl/sysdeps/i386/tls.h @@ -0,0 +1,429 @@ +/* Definition for thread-local data handling.  nptl/i386 version. +   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.  */ + +#ifndef _TLS_H +#define _TLS_H	1 + +#ifndef __ASSEMBLER__ +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> +# include <stdlib.h> +# include <list.h> + + +/* Type for the dtv.  */ +typedef union dtv +{ +  size_t counter; +  struct +  { +    void *val; +    bool is_static; +  } pointer; +} dtv_t; + + +typedef struct +{ +  void *tcb;		/* Pointer to the TCB.  Not necessarily the +			   thread descriptor used by libpthread.  */ +  dtv_t *dtv; +  void *self;		/* Pointer to the thread descriptor.  */ +  int multiple_threads; +  uintptr_t sysinfo; +  uintptr_t stack_guard; +} tcbhead_t; + +# define TLS_MULTIPLE_THREADS_IN_TCB 1 + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif + + +/* We require TLS support in the tools.  */ +#define HAVE_TLS_SUPPORT +#define HAVE___THREAD 1 +#define HAVE_TLS_MODEL_ATTRIBUTE 1 + +/* Signal that TLS support is available.  */ +#define USE_TLS	1 + +/* Alignment requirement for the stack.  For IA-32 this is governed by +   the SSE memory functions.  */ +#define STACK_ALIGN	16 + +#ifndef __ASSEMBLER__ +/* Get system call information.  */ +# include <sysdep.h> + +/* The old way: using LDT.  */ + +/* Structure passed to `modify_ldt', 'set_thread_area', and 'clone' calls.  */ +struct user_desc +{ +  unsigned int entry_number; +  unsigned long int base_addr; +  unsigned int limit; +  unsigned int seg_32bit:1; +  unsigned int contents:2; +  unsigned int read_exec_only:1; +  unsigned int limit_in_pages:1; +  unsigned int seg_not_present:1; +  unsigned int useable:1; +  unsigned int empty:25; +}; + +/* Initializing bit fields is slow.  We speed it up by using a union.  */ +union user_desc_init +{ +  struct user_desc desc; +  unsigned int vals[4]; +}; + + +/* This is the size of the initial TCB.  Can't be just sizeof (tcbhead_t), +   because NPTL getpid, __libc_alloca_cutoff etc. need (almost) the whole +   struct pthread even when not linked with -lpthread.  */ +# define TLS_INIT_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the initial TCB.  */ +# define TLS_INIT_TCB_ALIGN __alignof__ (struct pthread) + +/* This is the size of the TCB.  */ +# define TLS_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the TCB.  */ +# define TLS_TCB_ALIGN __alignof__ (struct pthread) + +/* Get the thread descriptor definition. */ +#include <descr.h> + +/* The TCB can have any size and the memory following the address the +   thread pointer points to is unspecified.  Allocate the TCB there.  */ +# define TLS_TCB_AT_TP	1 + + +/* Install the dtv pointer.  The pointer passed is to the element with +   index -1 which contain the length.  */ +# define INSTALL_DTV(descr, dtvp) \ +  ((tcbhead_t *) (descr))->dtv = (dtvp) + 1 + +/* Install new dtv for current thread.  */ +# define INSTALL_NEW_DTV(dtvp) \ +  ({ struct pthread *__pd;						      \ +     THREAD_SETMEM (__pd, header.dtv, (dtvp)); }) + +/* Return dtv of given thread descriptor.  */ +# define GET_DTV(descr) \ +  (((tcbhead_t *) (descr))->dtv) + +#define THREAD_SELF_SYSINFO	THREAD_GETMEM (THREAD_SELF, header.sysinfo) +#define THREAD_SYSINFO(pd)	((pd)->header.sysinfo) + +/* Macros to load from and store into segment registers.  */ +# ifndef TLS_GET_GS +#  define TLS_GET_GS() \ +  ({ int __seg; __asm__ ("movw %%gs, %w0" : "=q" (__seg)); __seg & 0xffff; }) +# endif +# ifndef TLS_SET_GS +#  define TLS_SET_GS(val) \ +  __asm__ ("movw %w0, %%gs" :: "q" (val)) +# endif + + +# ifndef __NR_set_thread_area +#  define __NR_set_thread_area 243 +# endif +# ifndef TLS_FLAG_WRITABLE +#  define TLS_FLAG_WRITABLE		0x00000001 +# endif + +// XXX Enable for the real world. +#if 0 +# ifndef __ASSUME_SET_THREAD_AREA +#  error "we need set_thread_area" +# endif +#endif + +# ifdef __PIC__ +#  define TLS_EBX_ARG "r" +#  define TLS_LOAD_EBX "xchgl %3, %%ebx\n\t" +# else +#  define TLS_EBX_ARG "b" +#  define TLS_LOAD_EBX +# endif + +#if defined NEED_DL_SYSINFO +# define INIT_SYSINFO \ +  _head->sysinfo = GLRO(dl_sysinfo) +#else +# define INIT_SYSINFO +#endif + +#ifndef LOCK_PREFIX +# ifdef UP +#  define LOCK_PREFIX  /* nothing */ +# else +#  define LOCK_PREFIX "lock;" +# endif +#endif + +/* Code to initially initialize the thread pointer.  This might need +   special attention since 'errno' is not yet available and if the +   operation can cause a failure 'errno' must not be touched.  */ +# define TLS_INIT_TP(thrdescr, secondcall) \ +  ({ void *_thrdescr = (thrdescr);					      \ +     tcbhead_t *_head = _thrdescr;					      \ +     union user_desc_init _segdescr;					      \ +     int _result;							      \ +									      \ +     _head->tcb = _thrdescr;						      \ +     /* For now the thread descriptor is at the same address.  */	      \ +     _head->self = _thrdescr;						      \ +     /* New syscall handling support.  */				      \ +     INIT_SYSINFO;							      \ +									      \ +     /* The 'entry_number' field.  Let the kernel pick a value.  */	      \ +     if (secondcall)							      \ +       _segdescr.vals[0] = TLS_GET_GS () >> 3;				      \ +     else								      \ +       _segdescr.vals[0] = -1;						      \ +     /* The 'base_addr' field.  Pointer to the TCB.  */			      \ +     _segdescr.vals[1] = (unsigned long int) _thrdescr;			      \ +     /* The 'limit' field.  We use 4GB which is 0xfffff pages.  */	      \ +     _segdescr.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 */						      \ +     _segdescr.vals[3] = 0x51;						      \ +									      \ +     /* Install the TLS.  */						      \ +     __asm__ volatile (TLS_LOAD_EBX					      \ +		   "int $0x80\n\t"					      \ +		   TLS_LOAD_EBX						      \ +		   : "=a" (_result), "=m" (_segdescr.desc.entry_number)	      \ +		   : "0" (__NR_set_thread_area),			      \ +		     TLS_EBX_ARG (&_segdescr.desc), "m" (_segdescr.desc));    \ +									      \ +     if (_result == 0)							      \ +       /* We know the index in the GDT, now load the segment register.	      \ +	  The use of the GDT is described by the value 3 in the lower	      \ +	  three bits of the segment descriptor value.			      \ +									      \ +	  Note that we have to do this even if the numeric value of	      \ +	  the descriptor does not change.  Loading the segment register	      \ +	  causes the segment information from the GDT to be loaded	      \ +	  which is necessary since we have changed it.   */		      \ +       TLS_SET_GS (_segdescr.desc.entry_number * 8 + 3);		      \ +									      \ +     _result == 0 ? NULL						      \ +     : "set_thread_area failed when setting up thread-local storage\n"; }) + + +/* Return the address of the dtv for the current thread.  */ +# define THREAD_DTV() \ +  ({ struct pthread *__pd;						      \ +     THREAD_GETMEM (__pd, header.dtv); }) + + +/* Return the thread descriptor for the current thread. + +   The contained asm must *not* be marked volatile since otherwise +   assignments like +        pthread_descr self = thread_self(); +   do not get optimized away.  */ +# define THREAD_SELF \ +  ({ struct pthread *__self;						      \ +     __asm__ ("movl %%gs:%c1,%0" : "=r" (__self)			      \ +	  : "i" (offsetof (struct pthread, header.self)));		      \ +     __self;}) + +/* Magic for libthread_db to know how to do THREAD_SELF.  */ +# define DB_THREAD_SELF \ +  REGISTER_THREAD_AREA (32, offsetof (struct user_regs_struct, xgs), 3) \ +  REGISTER_THREAD_AREA (64, 26 * 8, 3) /* x86-64's user_regs_struct->gs */ + + +/* Read member of the thread descriptor directly.  */ +# define THREAD_GETMEM(descr, member) \ +  ({ __typeof (descr->member) __value;					      \ +     if (sizeof (__value) == 1)						      \ +       __asm__ volatile ("movb %%gs:%P2,%b0"				      \ +		     : "=q" (__value)					      \ +		     : "0" (0), "i" (offsetof (struct pthread, member)));     \ +     else if (sizeof (__value) == 4)					      \ +       __asm__ volatile ("movl %%gs:%P1,%0"				      \ +		     : "=r" (__value)					      \ +		     : "i" (offsetof (struct pthread, member)));	      \ +     else								      \ +       {								      \ +	 if (sizeof (__value) != 8)					      \ +	   /* There should not be any value with a size other than 1,	      \ +	      4 or 8.  */						      \ +	   abort ();							      \ +									      \ +	 __asm__ volatile ("movl %%gs:%P1,%%eax\n\t"			      \ +		       "movl %%gs:%P2,%%edx"				      \ +		       : "=A" (__value)					      \ +		       : "i" (offsetof (struct pthread, member)),	      \ +			 "i" (offsetof (struct pthread, member) + 4));	      \ +       }								      \ +     __value; }) + + +/* Same as THREAD_GETMEM, but the member offset can be non-constant.  */ +# define THREAD_GETMEM_NC(descr, member, idx) \ +  ({ __typeof (descr->member[0]) __value;				      \ +     if (sizeof (__value) == 1)						      \ +       __asm__ volatile ("movb %%gs:%P2(%3),%b0"			      \ +		     : "=q" (__value)					      \ +		     : "0" (0), "i" (offsetof (struct pthread, member[0])),   \ +		     "r" (idx));					      \ +     else if (sizeof (__value) == 4)					      \ +       __asm__ volatile ("movl %%gs:%P1(,%2,4),%0"			      \ +		     : "=r" (__value)					      \ +		     : "i" (offsetof (struct pthread, member[0])),	      \ +		       "r" (idx));					      \ +     else								      \ +       {								      \ +	 if (sizeof (__value) != 8)					      \ +	   /* There should not be any value with a size other than 1,	      \ +	      4 or 8.  */						      \ +	   abort ();							      \ +									      \ +	 __asm__ volatile  ("movl %%gs:%P1(,%2,8),%%eax\n\t"		      \ +			"movl %%gs:4+%P1(,%2,8),%%edx"			      \ +			: "=&A" (__value)				      \ +			: "i" (offsetof (struct pthread, member[0])),	      \ +			  "r" (idx));					      \ +       }								      \ +     __value; }) + + +/* Same as THREAD_SETMEM, but the member offset can be non-constant.  */ +# define THREAD_SETMEM(descr, member, value) \ +  ({ if (sizeof (descr->member) == 1)					      \ +       __asm__ volatile ("movb %b0,%%gs:%P1" :				      \ +		     : "iq" (value),					      \ +		       "i" (offsetof (struct pthread, member)));	      \ +     else if (sizeof (descr->member) == 4)				      \ +       __asm__ volatile ("movl %0,%%gs:%P1" :				      \ +		     : "ir" (value),					      \ +		       "i" (offsetof (struct pthread, member)));	      \ +     else								      \ +       {								      \ +	 if (sizeof (descr->member) != 8)				      \ +	   /* There should not be any value with a size other than 1,	      \ +	      4 or 8.  */						      \ +	   abort ();							      \ +									      \ +	 __asm__ volatile ("movl %%eax,%%gs:%P1\n\t"			      \ +		       "movl %%edx,%%gs:%P2" :				      \ +		       : "A" (value),					      \ +			 "i" (offsetof (struct pthread, member)),	      \ +			 "i" (offsetof (struct pthread, member) + 4));	      \ +       }}) + + +/* Set member of the thread descriptor directly.  */ +# define THREAD_SETMEM_NC(descr, member, idx, value) \ +  ({ if (sizeof (descr->member[0]) == 1)				      \ +       __asm__ volatile ("movb %b0,%%gs:%P1(%2)" :			      \ +		     : "iq" (value),					      \ +		       "i" (offsetof (struct pthread, member)),		      \ +		       "r" (idx));					      \ +     else if (sizeof (descr->member[0]) == 4)				      \ +       __asm__ volatile ("movl %0,%%gs:%P1(,%2,4)" :			      \ +		     : "ir" (value),					      \ +		       "i" (offsetof (struct pthread, member)),		      \ +		       "r" (idx));					      \ +     else								      \ +       {								      \ +	 if (sizeof (descr->member[0]) != 8)				      \ +	   /* There should not be any value with a size other than 1,	      \ +	      4 or 8.  */						      \ +	   abort ();							      \ +									      \ +	 __asm__ volatile ("movl %%eax,%%gs:%P1(,%2,8)\n\t"		      \ +		       "movl %%edx,%%gs:4+%P1(,%2,8)" :			      \ +		       : "A" (value),					      \ +			 "i" (offsetof (struct pthread, member)),	      \ +			 "r" (idx));					      \ +       }}) + + +/* Atomic compare and exchange on TLS, returning old value.  */ +#define THREAD_ATOMIC_CMPXCHG_VAL(descr, member, newval, oldval) \ +  ({ __typeof (descr->member) __ret;					      \ +     __typeof (oldval) __old = (oldval);				      \ +     if (sizeof (descr->member) == 4)					      \ +       __asm__ volatile (LOCK_PREFIX "cmpxchgl %2, %%gs:%P3"		      \ +		     : "=a" (__ret)					      \ +		     : "0" (__old), "r" (newval),			      \ +		       "i" (offsetof (struct pthread, member)));	      \ +     else								      \ +       /* Not necessary for other sizes in the moment.  */		      \ +       abort ();							      \ +     __ret; }) + + +/* Atomic set bit.  */ +#define THREAD_ATOMIC_BIT_SET(descr, member, bit) \ +  (void) ({ if (sizeof ((descr)->member) == 4)				      \ +	      __asm__ volatile (LOCK_PREFIX "orl %1, %%gs:%P0"		      \ +			    :: "i" (offsetof (struct pthread, member)),	      \ +			       "ir" (1 << (bit)));			      \ +	    else							      \ +	      /* Not necessary for other sizes in the moment.  */	      \ +	      abort (); }) + + +/* Call the user-provided thread function.  */ +#define CALL_THREAD_FCT(descr) \ +  ({ void *__res;							      \ +     int __ignore1, __ignore2;						      \ +     __asm__ volatile ("pushl %%eax\n\t"					      \ +		   "pushl %%eax\n\t"					      \ +		   "pushl %%eax\n\t"					      \ +		   "pushl %%gs:%P4\n\t"					      \ +		   "call *%%gs:%P3\n\t"					      \ +		   "addl $16, %%esp"					      \ +		   : "=a" (__res), "=c" (__ignore1), "=d" (__ignore2)	      \ +		   : "i" (offsetof (struct pthread, start_routine)),	      \ +		     "i" (offsetof (struct pthread, arg)));		      \ +     __res; }) + + +/* Set the stack guard field in TCB head.  */ +#define THREAD_SET_STACK_GUARD(value) \ +  THREAD_SETMEM (THREAD_SELF, header.stack_guard, value) +#define THREAD_COPY_STACK_GUARD(descr) \ +  ((descr)->header.stack_guard						      \ +   = THREAD_GETMEM (THREAD_SELF, header.stack_guard)) + + +#endif /* __ASSEMBLER__ */ + +#endif	/* tls.h */ diff --git a/libpthread/nptl/sysdeps/mips/Makefile b/libpthread/nptl/sysdeps/mips/Makefile new file mode 100644 index 000000000..6371d2871 --- /dev/null +++ b/libpthread/nptl/sysdeps/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/mips/Makefile.arch b/libpthread/nptl/sysdeps/mips/Makefile.arch new file mode 100644 index 000000000..5d77b0074 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/Makefile.arch @@ -0,0 +1,65 @@ +# 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. +# + +libpthread_SSRC = pthread_spin_lock.S pthread_spin_trylock.S	\ +		  nptl-sysdep.S + +libc_a_CSRC = libc-tls.c + +CFLAGS-pt-raise.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +ASFLAGS-pthread_spin_lock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +ASFLAGS-pthread_spin_trylock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +ASFLAGS-nptl-sysdep.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1	\ +		        -I$(top_srcdir)libc/sysdeps/linux/mips + +CFLAGS-mips = $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +PTHREAD_ARCH_DIR := $(top_srcdir)libpthread/nptl/sysdeps/mips +PTHREAD_ARCH_OUT := $(top_builddir)libpthread/nptl/sysdeps/mips +PTHREAD_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_SSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(PTHREAD_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(PTHREAD_ARCH_OBJ) +endif +libpthread-so-y += $(PTHREAD_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y += $(PTHREAD_ARCH_OBJ) + +LIBC_ARCH_OBJ := $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(libc_a_CSRC)) + +libc-static-y += $(LIBC_ARCH_OBJ) + +libc-nomulti-y += $(LIBC_ARCH_OBJ) + +objclean-y += nptl_arch_objclean +headers_clean-y += nptl_arch_headers_clean + +# +# Create 'tcb-offsets.h' header file. +# +CFLAGS-tcb-offsets.c = -S + +$(PTHREAD_ARCH_OUT)/tcb-offsets.c: $(PTHREAD_ARCH_DIR)/tcb-offsets.sym +	awk -f $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_ARCH_OUT)/tcb-offsets.s: $(PTHREAD_ARCH_OUT)/tcb-offsets.c +	$(compile.c) + +nptl_arch_headers: $(PTHREAD_ARCH_OUT)/tcb-offsets.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_ARCH_OUT)/tcb-offsets.h + +nptl_arch_headers_clean: +	$(RM) $(PTHREAD_ARCH_OUT)/tcb-offsets.c		\ +	      $(PTHREAD_ARCH_OUT)/tcb-offsets.s		\ +	      $(PTHREAD_ARCH_OUT)/tcb-offsets.h + +nptl_arch_objclean: +	$(RM) $(PTHREAD_ARCH_OUT)/*.{o,os,oS} diff --git a/libpthread/nptl/sysdeps/mips/dl-tls.h b/libpthread/nptl/sysdeps/mips/dl-tls.h new file mode 100644 index 000000000..3ad3b2bc0 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/dl-tls.h @@ -0,0 +1,46 @@ +/* Thread-local storage handling in the ELF dynamic linker.  MIPS version. +   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.  */ + + +/* Type used for the representation of TLS information in the GOT.  */ +typedef struct +{ +  unsigned long int ti_module; +  unsigned long int ti_offset; +} tls_index; + +/* The thread pointer points 0x7000 past the first static TLS block.  */ +#define TLS_TP_OFFSET		0x7000 + +/* Dynamic thread vector pointers point 0x8000 past the start of each +   TLS block.  */ +#define TLS_DTV_OFFSET		0x8000 + +/* Compute the value for a GOTTPREL reloc.  */ +#define TLS_TPREL_VALUE(sym_map, sym_val) \ +  ((sym_map)->l_tls_offset + sym_val - TLS_TP_OFFSET) + +/* Compute the value for a DTPREL reloc.  */ +#define TLS_DTPREL_VALUE(sym_val) \ +  (sym_val - TLS_DTV_OFFSET) + +extern void *__tls_get_addr (tls_index *ti); + +# define GET_ADDR_OFFSET	(ti->ti_offset + TLS_DTV_OFFSET) +# define __TLS_GET_ADDR(__ti)	(__tls_get_addr (__ti) - TLS_DTV_OFFSET) diff --git a/libpthread/nptl/sysdeps/mips/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/mips/jmpbuf-unwind.h new file mode 100644 index 000000000..a9cfe43b3 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/jmpbuf-unwind.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2003, 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 <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ +  _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ +  ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[0].__sp - (_adj)) + +/* We use the normal longjmp for unwinding.  */ +#define __libc_unwind_longjmp(buf, val) longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/mips/libc-tls.c b/libpthread/nptl/sysdeps/mips/libc-tls.c new file mode 100644 index 000000000..fdedc9f5a --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/libc-tls.c @@ -0,0 +1,37 @@ +/* Thread-local storage handling in the ELF dynamic linker.  MIPS version. +   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 <../generic/libc-tls.c> +#include <dl-tls.h> + +#if USE_TLS + +/* On MIPS, linker optimizations are not required, so __tls_get_addr +   can be called even in statically linked binaries.  In this case module +   must be always 1 and PT_TLS segment exist in the binary, otherwise it +   would not link.  */ + +void * +__tls_get_addr (tls_index *ti) +{ +  dtv_t *dtv = THREAD_DTV (); +  return (char *) dtv[1].pointer.val + GET_ADDR_OFFSET; +} + +#endif diff --git a/libpthread/nptl/sysdeps/mips/nptl-sysdep.S b/libpthread/nptl/sysdeps/mips/nptl-sysdep.S new file mode 100644 index 000000000..7a4a8d311 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/nptl-sysdep.S @@ -0,0 +1,2 @@ +/* Pull in __syscall_error.  */ +#include <syscall_error.S> diff --git a/libpthread/nptl/sysdeps/mips/pthread_spin_lock.S b/libpthread/nptl/sysdeps/mips/pthread_spin_lock.S new file mode 100644 index 000000000..e35c381ed --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/pthread_spin_lock.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 <sys/asm.h> +#include <sysdep.h> +#include <sgidefs.h> + +ENTRY (pthread_spin_lock) +	.set	push +#if _MIPS_SIM == _ABIO32 +	.set	mips2 +#endif +1:	ll	a2, 0(a0) +	li	a1, 1 +	bnez	a2, 1b +	sc	a1, 0(a0) +	beqz	a1, 1b +	MIPS_SYNC +	.set	pop +	li	v0, 0 +	j	ra +	nop +END (pthread_spin_lock) diff --git a/libpthread/nptl/sysdeps/mips/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/mips/pthread_spin_trylock.S new file mode 100644 index 000000000..b54732869 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/pthread_spin_trylock.S @@ -0,0 +1,43 @@ +/* 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 <sys/asm.h> +#include <sysdep.h> +#define _ERRNO_H 1 +#include <bits/errno.h> +#include <sgidefs.h> + +ENTRY (pthread_spin_trylock) +	.set	push +#if _MIPS_SIM == _ABIO32 +	.set	mips2 +#endif +	ll	a2, 0(a0) +	li	a1, 1 +	bnez	a2, 1f +	sc	a1, 0(a0) +	beqz	a1, 1f +	MIPS_SYNC +	.set	pop +	li	v0, 0 +	j	ra +	nop +1:	li	v0, EBUSY +	j	ra +	nop +END (pthread_spin_trylock) diff --git a/libpthread/nptl/sysdeps/mips/pthreaddef.h b/libpthread/nptl/sysdeps/mips/pthreaddef.h new file mode 100644 index 000000000..e72b4bc58 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/pthreaddef.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2002, 2003, 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.  */ + +/* Default stack size.  */ +#define ARCH_STACK_DEFAULT_SIZE	(2 * 1024 * 1024) + +/* Required stack pointer alignment at beginning.  */ +#define STACK_ALIGN		16 + +/* Minimal stack size after allocating thread descriptor and guard size.  */ +#define MINIMAL_REST_STACK	2048 + +/* Alignment requirement for TCB.  */ +#define TCB_ALIGNMENT		16 + + +/* Location of current stack frame.  */ +#define CURRENT_STACK_FRAME	__builtin_frame_address (0) + + +/* XXX Until we have a better place keep the definitions here.  */ + +#define __exit_thread_inline(val) \ +  INLINE_SYSCALL (exit, 1, (val)) diff --git a/libpthread/nptl/sysdeps/mips/regdef.h b/libpthread/nptl/sysdeps/mips/regdef.h new file mode 100644 index 000000000..a462d512a --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/regdef.h @@ -0,0 +1,26 @@ +/* Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ralf Baechle <ralf@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.  */ + +#ifndef _REGDEF_H +#define _REGDEF_H + +#include <sys/regdef.h> +#include <sys/fpregdef.h> + +#endif /* _REGDEF_H */ diff --git a/libpthread/nptl/sysdeps/mips/sysdep.h b/libpthread/nptl/sysdeps/mips/sysdep.h new file mode 100644 index 000000000..69cecae70 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/sysdep.h @@ -0,0 +1,110 @@ +/* Copyright (C) 1992, 1995, 1997, 1999, 2000, 2002, 2003, 2004 +   Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Brendan Kehoe (brendan@zen.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 <sgidefs.h> +#include <sysdeps/generic/sysdep.h> + +#ifdef __ASSEMBLER__ + +#include <regdef.h> + +#define ENTRY(name) \ +  .globl name;								      \ +  .align 2;								      \ +  .ent name,0;								      \ +  name##: + +#undef END +#define	END(function)                                   \ +		.end	function;		        \ +		.size	function,.-function + +#define ret	j ra ; nop + +#undef PSEUDO_END +#define PSEUDO_END(sym) .end sym; .size sym,.-sym + +#define PSEUDO_NOERRNO(name, syscall_name, args)	\ +  .align 2;						\ +  ENTRY(name)						\ +  .set noreorder;					\ +  li v0, SYS_ify(syscall_name);				\ +  syscall + +#undef PSEUDO_END_NOERRNO +#define PSEUDO_END_NOERRNO(sym) .end sym; .size sym,.-sym + +#define ret_NOERRNO ret + +#define PSEUDO_ERRVAL(name, syscall_name, args)	\ +  .align 2;						\ +  ENTRY(name)						\ +  .set noreorder;					\ +  li v0, SYS_ify(syscall_name);				\ +  syscall + +#undef PSEUDO_END_ERRVAL +#define PSEUDO_END_ERRVAL(sym) .end sym; .size sym,.-sym + +#define ret_ERRVAL ret + +#define r0	v0 +#define r1	v1 +/* The mips move insn is d,s.  */ +#define MOVE(x,y)	move y , x + +#if _MIPS_SIM == _ABIO32 +# define L(label) $L ## label +#else +# define L(label) .L ## label +#endif + +/* Note that while it's better structurally, going back to call __syscall_error +   can make things confusing if you're debugging---it looks like it's jumping +   backwards into the previous fn.  */ +#ifdef __PIC__ +#define PSEUDO(name, syscall_name, args) \ +  .align 2;								      \ +  99: la t9,__syscall_error;						      \ +  jr t9;								      \ +  ENTRY(name)								      \ +  .set noreorder;							      \ +  .cpload t9;								      \ +  li v0, SYS_ify(syscall_name);						      \ +  syscall;								      \ +  .set reorder;								      \ +  bne a3, zero, 99b;							      \ +L(syse1): +#else +#define PSEUDO(name, syscall_name, args) \ +  .set noreorder;							      \ +  .align 2;								      \ +  99: j __syscall_error;						      \ +  nop;									      \ +  ENTRY(name)								      \ +  .set noreorder;							      \ +  li v0, SYS_ify(syscall_name);						      \ +  syscall;								      \ +  .set reorder;								      \ +  bne a3, zero, 99b;							      \ +L(syse1): +#endif + +#endif diff --git a/libpthread/nptl/sysdeps/mips/tcb-offsets.sym b/libpthread/nptl/sysdeps/mips/tcb-offsets.sym new file mode 100644 index 000000000..e0e71dc43 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/tcb-offsets.sym @@ -0,0 +1,11 @@ +#include <sysdep.h> +#include <tls.h> + +-- + +-- Abuse tls.h macros to derive offsets relative to the thread register. +#define thread_offsetof(mem)	(long)(offsetof(struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) + +MULTIPLE_THREADS_OFFSET		thread_offsetof (header.multiple_threads) +PID_OFFSET			thread_offsetof (pid) +TID_OFFSET			thread_offsetof (tid) diff --git a/libpthread/nptl/sysdeps/mips/tls.h b/libpthread/nptl/sysdeps/mips/tls.h new file mode 100644 index 000000000..0a83ac672 --- /dev/null +++ b/libpthread/nptl/sysdeps/mips/tls.h @@ -0,0 +1,159 @@ +/* Definition for thread-local data handling.  NPTL/MIPS version. +   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.  */ + +#ifndef _TLS_H +#define _TLS_H	1 + +#ifndef __ASSEMBLER__ +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> + +/* Type for the dtv.  */ +typedef union dtv +{ +  size_t counter; +  struct +  { +    void *val; +    bool is_static; +  } pointer; +} dtv_t; + +/* Note: rd must be $v1 to be ABI-conformant.  */ +# define READ_THREAD_POINTER() \ +    ({ void *__result;							      \ +       __asm__ __volatile__ (".set\tpush\n\t.set\tmips32r2\n\t"		      \ +		     "rdhwr\t%0, $29\n\t.set\tpop" : "=v" (__result));	      \ +       __result; }) + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> + +# define READ_THREAD_POINTER(rd) \ +	.set	push;							      \ +	.set	mips32r2;						      \ +	rdhwr	rd, $29;						      \ +	.set	pop +#endif /* __ASSEMBLER__ */ + + +/* We require TLS support in the tools.  */ +#define HAVE_TLS_SUPPORT		1 +#define HAVE_TLS_MODEL_ATTRIBUTE	1 +#define HAVE___THREAD			1 + +/* Signal that TLS support is available.  */ +#define USE_TLS	1 + +#ifndef __ASSEMBLER__ + +/* Get system call information.  */ +# include <sysdep.h> + +/* The TP points to the start of the thread blocks.  */ +# define TLS_DTV_AT_TP	1 + +/* Get the thread descriptor definition.  */ +#include <../../descr.h> + +typedef struct +{ +  dtv_t *dtv; +  void *private; +} tcbhead_t; + +/* This is the size of the initial TCB.  Because our TCB is before the thread +   pointer, we don't need this.  */ +# define TLS_INIT_TCB_SIZE	0 + +/* Alignment requirements for the initial TCB.  */ +# define TLS_INIT_TCB_ALIGN	__alignof__ (struct pthread) + +/* This is the size of the TCB.  Because our TCB is before the thread +   pointer, we don't need this.  */ +# define TLS_TCB_SIZE		0 + +/* Alignment requirements for the TCB.  */ +# define TLS_TCB_ALIGN		__alignof__ (struct pthread) + +/* This is the size we need before TCB - actually, it includes the TCB.  */ +# define TLS_PRE_TCB_SIZE \ +  (sizeof (struct pthread)						      \ +   + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1))) + +/* The thread pointer (in hardware register $29) points to the end of +   the TCB + 0x7000, as for PowerPC.  The pthread_descr structure is +   immediately in front of the TCB.  */ +# define TLS_TCB_OFFSET	0x7000 + +/* Install the dtv pointer.  The pointer passed is to the element with +   index -1 which contain the length.  */ +# define INSTALL_DTV(tcbp, dtvp) \ +  (((tcbhead_t *) (tcbp))[-1].dtv = (dtvp) + 1) + +/* Install new dtv for current thread.  */ +# define INSTALL_NEW_DTV(dtv) \ +  (THREAD_DTV() = (dtv)) + +/* Return dtv of given thread descriptor.  */ +# define GET_DTV(tcbp) \ +  (((tcbhead_t *) (tcbp))[-1].dtv) + +/* Code to initially initialize the thread pointer.  This might need +   special attention since 'errno' is not yet available and if the +   operation can cause a failure 'errno' must not be touched.  */ +# define TLS_INIT_TP(tcbp, secondcall) \ +  ({ INTERNAL_SYSCALL_DECL (err);					\ +     long result_var;							\ +     result_var = INTERNAL_SYSCALL (set_thread_area, err, 1,		\ +				    (char *) (tcbp) + TLS_TCB_OFFSET);	\ +     INTERNAL_SYSCALL_ERROR_P (result_var, err)				\ +       ? "unknown error" : NULL; }) + +/* Return the address of the dtv for the current thread.  */ +# define THREAD_DTV() \ +  (((tcbhead_t *) (READ_THREAD_POINTER () - TLS_TCB_OFFSET))[-1].dtv) + +/* Return the thread descriptor for the current thread.  */ +# define THREAD_SELF \ + ((struct pthread *) (READ_THREAD_POINTER ()			     \ +		      - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)) + +/* Magic for libthread_db to know how to do THREAD_SELF.  */ +# define DB_THREAD_SELF \ +  CONST_THREAD_AREA (32, TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE) + +/* Access to data in the thread descriptor is easy.  */ +# define THREAD_GETMEM(descr, member) \ +  descr->member +# define THREAD_GETMEM_NC(descr, member, idx) \ +  descr->member[idx] +# define THREAD_SETMEM(descr, member, value) \ +  descr->member = (value) +# define THREAD_SETMEM_NC(descr, member, idx, value) \ +  descr->member[idx] = (value) + +/* l_tls_offset == 0 is perfectly valid on MIPS, so we have to use some +   different value to mean unset l_tls_offset.  */ +# define NO_TLS_OFFSET		-1 + +#endif /* __ASSEMBLER__ */ + +#endif	/* tls.h */ diff --git a/libpthread/nptl/sysdeps/powerpc/Makefile b/libpthread/nptl/sysdeps/powerpc/Makefile new file mode 100644 index 000000000..3af245600 --- /dev/null +++ b/libpthread/nptl/sysdeps/powerpc/Makefile @@ -0,0 +1,21 @@ +# 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. + +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif diff --git a/libpthread/nptl/sysdeps/powerpc/dl-tls.h b/libpthread/nptl/sysdeps/powerpc/dl-tls.h new file mode 100644 index 000000000..957d4b4b9 --- /dev/null +++ b/libpthread/nptl/sysdeps/powerpc/dl-tls.h @@ -0,0 +1,49 @@ +/* Thread-local storage handling in the ELF dynamic linker.  PowerPC 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.  */ + + +/* Type used for the representation of TLS information in the TOC.  */ +typedef struct +{ +  unsigned long int ti_module; +  unsigned long int ti_offset; +} tls_index; + +/* The thread pointer points 0x7000 past the first static TLS block.  */ +#define TLS_TP_OFFSET		0x7000 + +/* Dynamic thread vector pointers point 0x8000 past the start of each +   TLS block.  */ +#define TLS_DTV_OFFSET		0x8000 + +/* Compute the value for a @tprel reloc.  */ +#define TLS_TPREL_VALUE(sym_map, sym, reloc) \ +  ((sym_map)->l_tls_offset + (sym)->st_value + (reloc)->r_addend \ +   - TLS_TP_OFFSET) + +/* Compute the value for a @dtprel reloc.  */ +#define TLS_DTPREL_VALUE(sym, reloc) \ +  ((sym)->st_value + (reloc)->r_addend - TLS_DTV_OFFSET) + +#ifdef SHARED +extern void *__tls_get_addr (tls_index *ti); + +# define GET_ADDR_OFFSET	(ti->ti_offset + TLS_DTV_OFFSET) +# define __TLS_GET_ADDR(__ti)	(__tls_get_addr (__ti) - TLS_DTV_OFFSET) +#endif diff --git a/libpthread/nptl/sysdeps/powerpc/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/powerpc/jmpbuf-unwind.h new file mode 100644 index 000000000..0b817160d --- /dev/null +++ b/libpthread/nptl/sysdeps/powerpc/jmpbuf-unwind.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2003, 2004 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 <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ +  _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ +  ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_GPR1] - (_adj)) + +/* We use the normal lobngjmp for unwinding.  */ +#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/powerpc/pthread_spin_lock.c b/libpthread/nptl/sysdeps/powerpc/pthread_spin_lock.c new file mode 100644 index 000000000..e2293fda1 --- /dev/null +++ b/libpthread/nptl/sysdeps/powerpc/pthread_spin_lock.c @@ -0,0 +1,45 @@ +/* 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 "pthreadP.h" + +int +pthread_spin_lock (lock) +     pthread_spinlock_t *lock; +{ +  unsigned int __tmp; + +  asm volatile ( +       "1:	lwarx	%0,0,%1\n" +       "	cmpwi	0,%0,0\n" +       "	bne-	2f\n" +       "	stwcx.	%2,0,%1\n" +       "	bne-	2f\n" +       "	isync\n" +       "	.subsection 1\n" +       "2:	lwzx	%0,0,%1\n" +       "	cmpwi	0,%0,0\n" +       "	bne	2b\n" +       "	b	1b\n" +       "	.previous" +       : "=&r" (__tmp) +       : "r" (lock), "r" (1) +       : "cr0", "memory"); +  return 0; +} diff --git a/libpthread/nptl/sysdeps/powerpc/pthread_spin_trylock.c b/libpthread/nptl/sysdeps/powerpc/pthread_spin_trylock.c new file mode 100644 index 000000000..d8e1dbcc8 --- /dev/null +++ b/libpthread/nptl/sysdeps/powerpc/pthread_spin_trylock.c @@ -0,0 +1,43 @@ +/* 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 "pthreadP.h" + +int +pthread_spin_trylock (lock) +     pthread_spinlock_t *lock; +{ +  unsigned int old; +  int err = EBUSY; + +  asm ("1:	lwarx	%0,0,%2\n" +       "	cmpwi	0,%0,0\n" +       "	bne	2f\n" +       "	stwcx.	%3,0,%2\n" +       "	bne-	1b\n" +       "	li	%1,0\n" +       "	isync\n" +       "2:	" +       : "=&r" (old), "=&r" (err) +       : "r" (lock), "r" (1), "1" (err) +       : "cr0", "memory"); + +  return err; +} diff --git a/libpthread/nptl/sysdeps/powerpc/pthreaddef.h b/libpthread/nptl/sysdeps/powerpc/pthreaddef.h new file mode 100644 index 000000000..342c15c67 --- /dev/null +++ b/libpthread/nptl/sysdeps/powerpc/pthreaddef.h @@ -0,0 +1,41 @@ +/* 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.  */ + +/* Default stack size.  */ +#define ARCH_STACK_DEFAULT_SIZE	(4 * 1024 * 1024) + +/* Required stack pointer alignment at beginning.  The ABI requires 16 +   bytes (for both 32-bit and 64-bit PowerPC).  */ +#define STACK_ALIGN		16 + +/* Minimal stack size after allocating thread descriptor and guard size.  */ +#define MINIMAL_REST_STACK	4096 + +/* Alignment requirement for TCB.  */ +#define TCB_ALIGNMENT		16 + + +/* Location of current stack frame.  */ +#define CURRENT_STACK_FRAME	__builtin_frame_address (0) + + +/* XXX Until we have a better place keep the definitions here.  */ + +/* While there is no such syscall.  */ +#define __exit_thread_inline(val) \ +  INLINE_SYSCALL (exit, 1, (val)) diff --git a/libpthread/nptl/sysdeps/powerpc/tcb-offsets.sym b/libpthread/nptl/sysdeps/powerpc/tcb-offsets.sym new file mode 100644 index 000000000..3962edbd5 --- /dev/null +++ b/libpthread/nptl/sysdeps/powerpc/tcb-offsets.sym @@ -0,0 +1,16 @@ +#include <sysdep.h> +#include <tls.h> + +-- + +-- Abuse tls.h macros to derive offsets relative to the thread register. +# undef __thread_register +# define __thread_register	((void *) 0) +# define thread_offsetof(mem)	((ptrdiff_t) THREAD_SELF + offsetof (struct pthread, mem)) + + +#if TLS_MULTIPLE_THREADS_IN_TCB +MULTIPLE_THREADS_OFFSET		thread_offsetof (header.multiple_threads) +#endif +PID				thread_offsetof (pid) +TID				thread_offsetof (tid) diff --git a/libpthread/nptl/sysdeps/powerpc/tls.h b/libpthread/nptl/sysdeps/powerpc/tls.h new file mode 100644 index 000000000..1157116a3 --- /dev/null +++ b/libpthread/nptl/sysdeps/powerpc/tls.h @@ -0,0 +1,173 @@ +/* Definition for thread-local data handling.  NPTL/PowerPC version. +   Copyright (C) 2003, 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.  */ + +#ifndef _TLS_H +#define _TLS_H	1 + +#ifndef __ASSEMBLER__ +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> + +/* Type for the dtv.  */ +typedef union dtv +{ +  size_t counter; +  struct +  { +    void *val; +    bool is_static; +  } pointer; +} dtv_t; + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif /* __ASSEMBLER__ */ + + +/* We require TLS support in the tools.  */ +#ifndef HAVE_TLS_SUPPORT +# error "TLS support is required." +#endif + +/* Signal that TLS support is available.  */ +# define USE_TLS	1 + +#ifndef __ASSEMBLER__ + +/* Get system call information.  */ +# include <sysdep.h> + +/* The TP points to the start of the thread blocks.  */ +# define TLS_DTV_AT_TP	1 + +/* We use the multiple_threads field in the pthread struct */ +#define TLS_MULTIPLE_THREADS_IN_TCB	1 + +/* Get the thread descriptor definition.  */ +# include <nptl/descr.h> + +/* The stack_guard is accessed directly by GCC -fstack-protector code, +   so it is a part of public ABI.  The dtv field is private.  */ +typedef struct +{ +  uintptr_t stack_guard; +  dtv_t *dtv; +} tcbhead_t; + +/* This is the size of the initial TCB.  */ +# define TLS_INIT_TCB_SIZE	0 + +/* Alignment requirements for the initial TCB.  */ +# define TLS_INIT_TCB_ALIGN	__alignof__ (struct pthread) + +/* This is the size of the TCB.  */ +# define TLS_TCB_SIZE		0 + +/* Alignment requirements for the TCB.  */ +# define TLS_TCB_ALIGN		__alignof__ (struct pthread) + +/* This is the size we need before TCB.  */ +# define TLS_PRE_TCB_SIZE \ +  (sizeof (struct pthread)						      \ +   + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1))) + +# ifndef __powerpc64__ +/* Register r2 (tp) is reserved by the ABI as "thread pointer". */ +register void *__thread_register __asm__ ("r2"); +#  define PT_THREAD_POINTER PT_R2 +# else +/* Register r13 (tp) is reserved by the ABI as "thread pointer". */ +register void *__thread_register __asm__ ("r13"); +#  define PT_THREAD_POINTER PT_R13 +# endif + +/* The following assumes that TP (R2 or R13) points to the end of the +   TCB + 0x7000 (per the ABI).  This implies that TCB address is +   TP - 0x7000.  As we define TLS_DTV_AT_TP we can +   assume that the pthread struct is allocated immediately ahead of the +   TCB.  This implies that the pthread_descr address is +   TP - (TLS_PRE_TCB_SIZE + 0x7000).  */ +# define TLS_TCB_OFFSET	0x7000 + +/* Install the dtv pointer.  The pointer passed is to the element with +   index -1 which contain the length.  */ +# define INSTALL_DTV(tcbp, dtvp) \ +  ((tcbhead_t *) (tcbp))[-1].dtv = dtvp + 1 + +/* Install new dtv for current thread.  */ +# define INSTALL_NEW_DTV(dtv) (THREAD_DTV() = (dtv)) + +/* Return dtv of given thread descriptor.  */ +# define GET_DTV(tcbp)	(((tcbhead_t *) (tcbp))[-1].dtv) + +/* Code to initially initialize the thread pointer.  This might need +   special attention since 'errno' is not yet available and if the +   operation can cause a failure 'errno' must not be touched.  */ +# define TLS_INIT_TP(tcbp, secondcall) \ +    (__thread_register = (void *) (tcbp) + TLS_TCB_OFFSET, NULL) + +/* Return the address of the dtv for the current thread.  */ +# define THREAD_DTV() \ +    (((tcbhead_t *) (__thread_register - TLS_TCB_OFFSET))[-1].dtv) + +/* Return the thread descriptor for the current thread.  */ +# define THREAD_SELF \ +    ((struct pthread *) (__thread_register \ +			 - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)) + +/* Magic for libthread_db to know how to do THREAD_SELF.  */ +# define DB_THREAD_SELF							      \ +  REGISTER (32, 32, PT_THREAD_POINTER * 4,				      \ +	    - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)			      \ +  REGISTER (64, 64, PT_THREAD_POINTER * 8,				      \ +	    - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) + +/* Read member of the thread descriptor directly.  */ +# define THREAD_GETMEM(descr, member) ((void)(descr), (THREAD_SELF)->member) + +/* Same as THREAD_GETMEM, but the member offset can be non-constant.  */ +# define THREAD_GETMEM_NC(descr, member, idx) \ +    ((void)(descr), (THREAD_SELF)->member[idx]) + +/* Set member of the thread descriptor directly.  */ +# define THREAD_SETMEM(descr, member, value) \ +    ((void)(descr), (THREAD_SELF)->member = (value)) + +/* Same as THREAD_SETMEM, but the member offset can be non-constant.  */ +# define THREAD_SETMEM_NC(descr, member, idx, value) \ +    ((void)(descr), (THREAD_SELF)->member[idx] = (value)) + +/* Set the stack guard field in TCB head.  */ +# define THREAD_SET_STACK_GUARD(value) \ +    (((tcbhead_t *) ((char *) __thread_register				      \ +		     - TLS_TCB_OFFSET))[-1].stack_guard = (value)) +# define THREAD_COPY_STACK_GUARD(descr) \ +    (((tcbhead_t *) ((char *) (descr)					      \ +		     + TLS_PRE_TCB_SIZE))[-1].stack_guard		      \ +     = ((tcbhead_t *) ((char *) __thread_register			      \ +		       - TLS_TCB_OFFSET))[-1].stack_guard) + +/* l_tls_offset == 0 is perfectly valid on PPC, so we have to use some +   different value to mean unset l_tls_offset.  */ +# define NO_TLS_OFFSET		-1 + +#endif /* __ASSEMBLER__ */ + +#endif	/* tls.h */ diff --git a/libpthread/nptl/sysdeps/pthread/Makefile b/libpthread/nptl/sysdeps/pthread/Makefile new file mode 100644 index 000000000..a30ded527 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/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/pthread/Makefile.in b/libpthread/nptl/sysdeps/pthread/Makefile.in new file mode 100644 index 000000000..0d1097929 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/Makefile.in @@ -0,0 +1,153 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005-2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +# +# NOTE: glibc puts flockfile.c, ftrylockfile.c, funlockfile.c, and +#       pt-longjmp.c in libc and libpthread. For uClibc, they are +#       in libc only. +# +libpthread_CSRC = pthread_barrier_wait.c pthread_cond_broadcast.c	\ +		  pthread_cond_signal.c pthread_cond_timedwait.c	\ +		  pthread_cond_wait.c pthread_rwlock_rdlock.c		\ +		  pthread_rwlock_timedrdlock.c				\ +		  pthread_rwlock_timedwrlock.c pthread_rwlock_unlock.c	\ +		  pthread_rwlock_wrlock.c pthread_sigmask.c		\ +		  pthread_spin_destroy.c pthread_spin_init.c		\ +		  pthread_spin_unlock.c pt-sigfillset.c	\ +		  pt-longjmp.c + + +ifeq ($(TARGET_ARCH),i386) +X86_PTHREAD_EXCLUDE_LIST = pthread_spin_unlock.c pthread_spin_init.c \ +		pthread_barrier_wait.c pthread_cond_broadcast.c	\ +		pthread_cond_signal.c pthread_rwlock_timedrdlock.c	\ +		pthread_rwlock_timedwrlock.c pthread_rwlock_unlock.c pthread_rwlock_wrlock.c \ +		pthread_rwlock_rdlock.c + +libpthread_CSRC := $(filter-out $(X86_PTHREAD_EXCLUDE_LIST),$(libpthread_CSRC)) +endif + +ifeq ($(TARGET_ARCH),sh) +SH_PTHREAD_EXCLUDE_LIST = pthread_spin_unlock.c pthread_spin_init.c \ +		pthread_rwlock_wrlock.c pthread_rwlock_rdlock.c \ +		pthread_rwlock_unlock.c pt-longjmp.c \ +		pthread_barrier_wait.c pthread_cond_broadcast.c	\ +		pthread_cond_signal.c \ +		pthread_rwlock_timedrdlock.c \ +		pthread_rwlock_timedwrlock.c + +libpthread_CSRC := $(filter-out $(SH_PTHREAD_EXCLUDE_LIST),$(libpthread_CSRC)) +endif + +ifeq ($(TARGET_ARCH),x86_64) +X64_PTHREAD_EXCLUDE_LIST = pthread_spin_unlock.c pthread_spin_init.c \ +		pthread_barrier_wait.c pthread_cond_broadcast.c	\ +		pthread_cond_signal.c pthread_rwlock_timedrdlock.c	\ +		pthread_rwlock_timedwrlock.c pthread_rwlock_unlock.c pthread_rwlock_wrlock.c \ +		pthread_rwlock_rdlock.c pthread_cond_timedwait.c + +libpthread_CSRC := $(filter-out $(X64_PTHREAD_EXCLUDE_LIST),$(libpthread_CSRC)) +endif + + + +CFLAGS-pt-common = -DNOT_IN_libc=1 $(SSP_ALL_CFLAGS) + +CFLAGS-pthread_barrier_wait.c = -D_GNU_SOURCE $(CFLAGS-pt-common)	\ +				-DIS_IN_libpthread=1 +CFLAGS-pthread_cond_broadcast.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_cond_signal.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_cond_timedwait.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_cond_wait.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_rwlock_rdlock.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_rwlock_timedrdlock.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_rwlock_timedwrlock.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_rwlock_unlock.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_rwlock_wrlock.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_sigmask.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 +CFLAGS-pthread_spin_destroy.c = -D_GNU_SOURCE $(CFLAGS-pt-common)	\ +				-DIS_IN_libpthread=1 +CFLAGS-pthread_spin_init.c = -D_GNU_SOURCE $(CFLAGS-pt-common)		\ +			     -DIS_IN_libpthread=1 +CFLAGS-pthread_spin_unlock.c = -D_GNU_SOURCE $(CFLAGS-pt-common)	\ +			       -DIS_IN_libpthread=1 +CFLAGS-pt-sigaction.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1	\ +		     -I$(top_srcdir)libc/sysdeps/linux/$(TARGET_ARCH)	\ +		     -I$(top_srcdir)libc/signal +CFLAGS-pt-sigfillset.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1	\ +		      -I$(top_srcdir)libc/signal +CFLAGS-pt-sigprocmask.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1	\ +		       -I$(top_srcdir)libc/sysdeps/linux/common +CFLAGS-unwind-forcedunwind.c = $(CFLAGS-pt-common) -DIS_IN_libpthread=1 -fexceptions -fasynchronous-unwind-tables +CFLAGS-librt-cancellation.c = -DIS_IN_librt=1 $(CFLAGS-pt-common)	\ +			      -fexceptions -fasynchronous-unwind-tables +CFLAGS-rt-unwind-resume.c = -DIS_IN_librt=1 $(CFLAGS-pt-common)		\ +			    -fexceptions -fasynchronous-unwind-tables + +#CFLAGS:=$(CFLAGS:-O1=-O2) + +pthread_DIR := $(top_srcdir)libpthread/nptl/sysdeps/pthread +pthread_OUT := $(top_builddir)libpthread/nptl/sysdeps/pthread + +pthread_SRC = $(patsubst %.c, $(pthread_DIR)/%.c, $(libpthread_CSRC)) +pthread_OBJ = $(patsubst %.c, $(pthread_OUT)/%.o, $(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(pthread_OBJ:.o=.os) +else +libpthread-a-y += $(pthread_OBJ) +endif +libpthread-so-y += $(pthread_OBJ:.o=.oS) +libpthread-so-y += $(pthread_OUT)/pt-sigaction.oS $(pthread_OUT)/pt-sigprocmask.oS \ +					$(pthread_OUT)/unwind-forcedunwind.oS + +CFLAGS-sigaction.c = -I$(top_srcdir)libc/signal +libc-y += $(pthread_OUT)/sigaction.o + +librt-a-y += $(pthread_OUT)/librt-cancellation.o +librt-so-y += $(pthread_OUT)/librt-cancellation.oS		\ +	      $(pthread_OUT)/rt-unwind-resume.oS + +ifeq ($(UCLIBC_CTOR_DTOR),y) +CFLAGS-pt-initfini.c = -S -g0 -fPIC -fno-inline-functions	\ +		       $(call check_gcc,-fno-unit-at-a-time,)	\ +		       -finhibit-size-directive			\ +		       $(patsubst -f%,-fno-%,$(call check_gcc,-fexceptions,)) +ASFLAGS-crti.S = -g0 +ASFLAGS-crtn.S = -g0 + +$(pthread_OUT)/pt-initfini.s: $(pthread_DIR)/pt-initfini.c +	$(compile.c) +	sed -n -e '/@TESTS_BEGIN/,/@TESTS_END/p' $< | \ +		awk -f $(pthread_DIR)/defs.awk > $(pthread_OUT)/defs.h + +$(pthread_OUT)/crti.S: $(pthread_OUT)/pt-initfini.s +	sed -n -e '1,/@HEADER_ENDS/p' \ +	       -e '/@_.*_PROLOG_BEGINS/,/@_.*_PROLOG_ENDS/p' \ +	       -e '/@TRAILER_BEGINS/,$$p' $< > $@ + +$(pthread_OUT)/crtn.S: $(pthread_OUT)/pt-initfini.s +	sed -n -e '1,/@HEADER_ENDS/p' \ +	       -e '/@_.*_EPILOG_BEGINS/,/@_.*_EPILOG_ENDS/p' \ +	       -e '/@TRAILER_BEGINS/,$$p' $< > $@ +endif + +$(pthread_DIR)/pt-sigaction.c: +	$(LN) -s sigaction.c $@ + +$(pthread_DIR)/pt-sigfillset.c: +	$(LN) -s sigfillset.c $@ + +$(pthread_DIR)/pt-sigprocmask.c: +	$(LN) -s sigprocmask.c $@ + +objclean-y += nptl_pthread_clean + +nptl_pthread_clean: +	$(do_rm) $(addprefix $(pthread_OUT)/*., o os oS s S) $(pthread_OUT)/defs.h \ +	      $(pthread_DIR)/pt-sigaction.c $(pthread_DIR)/pt-sigfillset.c \ +	      $(pthread_DIR)/pt-sigprocmask.c diff --git a/libpthread/nptl/sysdeps/pthread/allocalim.h b/libpthread/nptl/sysdeps/pthread/allocalim.h new file mode 100644 index 000000000..35224ec74 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/allocalim.h @@ -0,0 +1,29 @@ +/* Determine whether block of given size can be allocated on the stack or not. +   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 Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General 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 <alloca.h> +#include <limits.h> + + +extern inline int +__libc_use_alloca (size_t size) +{ +  return (__builtin_expect (size <= PTHREAD_STACK_MIN / 4, 1) +	  || __libc_alloca_cutoff (size)); +} diff --git a/libpthread/nptl/sysdeps/pthread/bits/libc-lock.h b/libpthread/nptl/sysdeps/pthread/bits/libc-lock.h new file mode 100644 index 000000000..c59e3a0cc --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/bits/libc-lock.h @@ -0,0 +1,566 @@ +/* libc-internal interface for mutex locks.  NPTL version. +   Copyright (C) 1996-2001, 2002, 2003, 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; 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_LIBC_LOCK_H +#define _BITS_LIBC_LOCK_H 1 + +#include <pthread.h> +#define __need_NULL +#include <stddef.h> + + +/* Fortunately Linux now has a mean to do locking which is realtime +   safe without the aid of the thread library.  We also need no fancy +   options like error checking mutexes etc.  We only need simple +   locks, maybe recursive.  This can be easily and cheaply implemented +   using futexes.  We will use them everywhere except in ld.so since +   ld.so might be used on old kernels with a different libc.so.  */ +#ifdef _LIBC +# include <lowlevellock.h> +# include <tls.h> +# include <pthread-functions.h> +#endif + +/* Mutex type.  */ +#if defined _LIBC || defined _IO_MTSAFE_IO +# if (defined NOT_IN_libc && !defined IS_IN_libpthread) || !defined _LIBC +typedef pthread_mutex_t __libc_lock_t; +typedef struct { pthread_mutex_t mutex; } __libc_lock_recursive_t; +# else +typedef int __libc_lock_t; +typedef struct { int lock; int cnt; void *owner; } __libc_lock_recursive_t; +# endif +typedef struct { pthread_mutex_t mutex; } __rtld_lock_recursive_t; +# ifdef __USE_UNIX98 +typedef pthread_rwlock_t __libc_rwlock_t; +# else +typedef struct __libc_rwlock_opaque__ __libc_rwlock_t; +# endif +#else +typedef struct __libc_lock_opaque__ __libc_lock_t; +typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t; +typedef struct __libc_rwlock_opaque__ __libc_rwlock_t; +#endif + +/* Type for key to thread-specific data.  */ +typedef pthread_key_t __libc_key_t; + +/* Define a lock variable NAME with storage class CLASS.  The lock must be +   initialized with __libc_lock_init before it can be used (or define it +   with __libc_lock_define_initialized, below).  Use `extern' for CLASS to +   declare a lock defined in another module.  In public structure +   definitions you must use a pointer to the lock structure (i.e., NAME +   begins with a `*'), because its storage size will not be known outside +   of libc.  */ +#define __libc_lock_define(CLASS,NAME) \ +  CLASS __libc_lock_t NAME; +#define __libc_rwlock_define(CLASS,NAME) \ +  CLASS __libc_rwlock_t NAME; +#define __libc_lock_define_recursive(CLASS,NAME) \ +  CLASS __libc_lock_recursive_t NAME; +#define __rtld_lock_define_recursive(CLASS,NAME) \ +  CLASS __rtld_lock_recursive_t NAME; + +/* Define an initialized lock variable NAME with storage class CLASS. + +   For the C library we take a deeper look at the initializer.  For +   this implementation all fields are initialized to zero.  Therefore +   we don't initialize the variable which allows putting it into the +   BSS section.  (Except on PA-RISC and other odd architectures, where +   initialized locks must be set to one due to the lack of normal +   atomic operations.) */ + +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# if LLL_LOCK_INITIALIZER == 0 +#  define __libc_lock_define_initialized(CLASS,NAME) \ +  CLASS __libc_lock_t NAME; +# else +#  define __libc_lock_define_initialized(CLASS,NAME) \ +  CLASS __libc_lock_t NAME = LLL_LOCK_INITIALIZER; +# endif +#else +# if __LT_SPINLOCK_INIT == 0 +#  define __libc_lock_define_initialized(CLASS,NAME) \ +  CLASS __libc_lock_t NAME; +# else +#  define __libc_lock_define_initialized(CLASS,NAME) \ +  CLASS __libc_lock_t NAME = PTHREAD_MUTEX_INITIALIZER; +# endif +#endif + +#define __libc_rwlock_define_initialized(CLASS,NAME) \ +  CLASS __libc_rwlock_t NAME = PTHREAD_RWLOCK_INITIALIZER; + +/* Define an initialized recursive lock variable NAME with storage +   class CLASS.  */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# if LLL_LOCK_INITIALIZER == 0 +#  define __libc_lock_define_initialized_recursive(CLASS,NAME) \ +  CLASS __libc_lock_recursive_t NAME; +# else +#  define __libc_lock_define_initialized_recursive(CLASS,NAME) \ +  CLASS __libc_lock_recursive_t NAME = _LIBC_LOCK_RECURSIVE_INITIALIZER; +# endif +# define _LIBC_LOCK_RECURSIVE_INITIALIZER \ +  { LLL_LOCK_INITIALIZER, 0, NULL } +#else +# define __libc_lock_define_initialized_recursive(CLASS,NAME) \ +  CLASS __libc_lock_recursive_t NAME = _LIBC_LOCK_RECURSIVE_INITIALIZER; +# define _LIBC_LOCK_RECURSIVE_INITIALIZER \ +  {PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP} +#endif + +#define __rtld_lock_define_initialized_recursive(CLASS,NAME) \ +  CLASS __rtld_lock_recursive_t NAME = _RTLD_LOCK_RECURSIVE_INITIALIZER; +#define _RTLD_LOCK_RECURSIVE_INITIALIZER \ +  {PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP} + +#define __rtld_lock_initialize(NAME) \ +  (void) ((NAME) = (__rtld_lock_recursive_t) _RTLD_LOCK_RECURSIVE_INITIALIZER) + +/* If we check for a weakly referenced symbol and then perform a +   normal jump to it te code generated for some platforms in case of +   PIC is unnecessarily slow.  What would happen is that the function +   is first referenced as data and then it is called indirectly +   through the PLT.  We can make this a direct jump.  */ +#ifdef __PIC__ +# define __libc_maybe_call(FUNC, ARGS, ELSE) \ +  (__extension__ ({ __typeof (FUNC) *_fn = (FUNC); \ +                    _fn != NULL ? (*_fn) ARGS : ELSE; })) +#else +# define __libc_maybe_call(FUNC, ARGS, ELSE) \ +  (FUNC != NULL ? FUNC ARGS : ELSE) +#endif + +/* Call thread functions through the function pointer table.  */ +#if defined SHARED && !defined NOT_IN_libc +# define PTF(NAME) __libc_pthread_functions.ptr_##NAME +# define __libc_ptf_call(FUNC, ARGS, ELSE) \ +  (PTF(FUNC) != NULL ? PTF(FUNC) ARGS : ELSE) +#else +# define PTF(NAME) NAME +# define __libc_ptf_call(FUNC, ARGS, ELSE) \ +  __libc_maybe_call (FUNC, ARGS, ELSE) +#endif + + +/* Initialize the named lock variable, leaving it in a consistent, unlocked +   state.  */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_init(NAME) ((NAME) = LLL_LOCK_INITIALIZER, 0) +#else +# define __libc_lock_init(NAME) \ +  __libc_maybe_call (__pthread_mutex_init, (&(NAME), NULL), 0) +#endif +#define __libc_rwlock_init(NAME) \ +  __libc_maybe_call (__pthread_rwlock_init, (&(NAME), NULL), 0) + +/* Same as last but this time we initialize a recursive mutex.  */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_init_recursive(NAME) \ +  ((NAME) = (__libc_lock_recursive_t) _LIBC_LOCK_RECURSIVE_INITIALIZER, 0) +#else +# define __libc_lock_init_recursive(NAME) \ +  do {									      \ +    if (__pthread_mutex_init != NULL)					      \ +      {									      \ +	pthread_mutexattr_t __attr;					      \ +	__pthread_mutexattr_init (&__attr);				      \ +	__pthread_mutexattr_settype (&__attr, PTHREAD_MUTEX_RECURSIVE_NP);    \ +	__pthread_mutex_init (&(NAME).mutex, &__attr);			      \ +	__pthread_mutexattr_destroy (&__attr);				      \ +      }									      \ +  } while (0) +#endif + +#define __rtld_lock_init_recursive(NAME) \ +  do {									      \ +    if (__pthread_mutex_init != NULL)					      \ +      {									      \ +	pthread_mutexattr_t __attr;					      \ +	__pthread_mutexattr_init (&__attr);				      \ +	__pthread_mutexattr_settype (&__attr, PTHREAD_MUTEX_RECURSIVE_NP);    \ +	__pthread_mutex_init (&(NAME).mutex, &__attr);			      \ +	__pthread_mutexattr_destroy (&__attr);				      \ +      }									      \ +  } while (0) + +/* Finalize the named lock variable, which must be locked.  It cannot be +   used again until __libc_lock_init is called again on it.  This must be +   called on a lock variable before the containing storage is reused.  */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_fini(NAME) ((void) 0) +#else +# define __libc_lock_fini(NAME) \ +  __libc_maybe_call (__pthread_mutex_destroy, (&(NAME)), 0) +#endif +#define __libc_rwlock_fini(NAME) \ +  __libc_maybe_call (__pthread_rwlock_destroy, (&(NAME)), 0) + +/* Finalize recursive named lock.  */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_fini_recursive(NAME) ((void) 0) +#else +# define __libc_lock_fini_recursive(NAME) \ +  __libc_maybe_call (__pthread_mutex_destroy, (&(NAME)), 0) +#endif + +/* Lock the named lock variable.  */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_lock(NAME) \ +  ({ lll_lock (NAME); 0; }) +#else +# define __libc_lock_lock(NAME) \ +  __libc_maybe_call (__pthread_mutex_lock, (&(NAME)), 0) +#endif +#define __libc_rwlock_rdlock(NAME) \ +  __libc_ptf_call (__pthread_rwlock_rdlock, (&(NAME)), 0) +#define __libc_rwlock_wrlock(NAME) \ +  __libc_ptf_call (__pthread_rwlock_wrlock, (&(NAME)), 0) + +/* Lock the recursive named lock variable.  */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_lock_recursive(NAME) \ +  do {									      \ +    void *self = THREAD_SELF;						      \ +    if ((NAME).owner != self)						      \ +      {									      \ +	lll_lock ((NAME).lock);						      \ +	(NAME).owner = self;						      \ +      }									      \ +    ++(NAME).cnt;							      \ +  } while (0) +#else +# define __libc_lock_lock_recursive(NAME) \ +  __libc_maybe_call (__pthread_mutex_lock, (&(NAME).mutex), 0) +#endif + +/* Try to lock the named lock variable.  */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_trylock(NAME) \ +  lll_trylock (NAME) +#else +# define __libc_lock_trylock(NAME) \ +  __libc_maybe_call (__pthread_mutex_trylock, (&(NAME)), 0) +#endif +#define __libc_rwlock_tryrdlock(NAME) \ +  __libc_maybe_call (__pthread_rwlock_tryrdlock, (&(NAME)), 0) +#define __libc_rwlock_trywrlock(NAME) \ +  __libc_maybe_call (__pthread_rwlock_trywrlock, (&(NAME)), 0) + +/* Try to lock the recursive named lock variable.  */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_trylock_recursive(NAME) \ +  ({									      \ +    int result = 0;							      \ +    void *self = THREAD_SELF;						      \ +    if ((NAME).owner != self)						      \ +      {									      \ +	if (lll_trylock ((NAME).lock) == 0)				      \ +	  {								      \ +	    (NAME).owner = self;					      \ +	    (NAME).cnt = 1;						      \ +	  }								      \ +	else								      \ +	  result = EBUSY;						      \ +      }									      \ +    else								      \ +      ++(NAME).cnt;							      \ +    result;								      \ +  }) +#else +# define __libc_lock_trylock_recursive(NAME) \ +  __libc_maybe_call (__pthread_mutex_trylock, (&(NAME)), 0) +#endif + +#define __rtld_lock_trylock_recursive(NAME) \ +  __libc_maybe_call (__pthread_mutex_trylock, (&(NAME).mutex), 0) + +/* Unlock the named lock variable.  */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define __libc_lock_unlock(NAME) \ +  lll_unlock (NAME) +#else +# define __libc_lock_unlock(NAME) \ +  __libc_maybe_call (__pthread_mutex_unlock, (&(NAME)), 0) +#endif +#define __libc_rwlock_unlock(NAME) \ +  __libc_ptf_call (__pthread_rwlock_unlock, (&(NAME)), 0) + +/* Unlock the recursive named lock variable.  */ +#if defined _LIBC && (!defined NOT_IN_libc || defined IS_IN_libpthread) +/* We do no error checking here.  */ +# define __libc_lock_unlock_recursive(NAME) \ +  do {									      \ +    if (--(NAME).cnt == 0)						      \ +      {									      \ +	(NAME).owner = NULL;						      \ +	lll_unlock ((NAME).lock);					      \ +      }									      \ +  } while (0) +#else +# define __libc_lock_unlock_recursive(NAME) \ +  __libc_maybe_call (__pthread_mutex_unlock, (&(NAME)), 0) +#endif + +#if defined _LIBC && defined SHARED +# define __rtld_lock_default_lock_recursive(lock) \ +  ++((pthread_mutex_t *)(lock))->__data.__count; + +# define __rtld_lock_default_unlock_recursive(lock) \ +  --((pthread_mutex_t *)(lock))->__data.__count; + +# define __rtld_lock_lock_recursive(NAME) \ +  GL(dl_rtld_lock_recursive) (&(NAME).mutex) + +# define __rtld_lock_unlock_recursive(NAME) \ +  GL(dl_rtld_unlock_recursive) (&(NAME).mutex) +#else +# define __rtld_lock_lock_recursive(NAME) \ +  __libc_maybe_call (__pthread_mutex_lock, (&(NAME).mutex), 0) + +# define __rtld_lock_unlock_recursive(NAME) \ +  __libc_maybe_call (__pthread_mutex_unlock, (&(NAME).mutex), 0) +#endif + +/* Define once control variable.  */ +#if PTHREAD_ONCE_INIT == 0 +/* Special case for static variables where we can avoid the initialization +   if it is zero.  */ +# define __libc_once_define(CLASS, NAME) \ +  CLASS pthread_once_t NAME +#else +# define __libc_once_define(CLASS, NAME) \ +  CLASS pthread_once_t NAME = PTHREAD_ONCE_INIT +#endif + +/* Call handler iff the first call.  */ +#define __libc_once(ONCE_CONTROL, INIT_FUNCTION) \ +  do {									      \ +    if (PTF(__pthread_once) != NULL)					      \ +      PTF(__pthread_once) (&(ONCE_CONTROL), INIT_FUNCTION);		      \ +    else if ((ONCE_CONTROL) == PTHREAD_ONCE_INIT) {			      \ +      INIT_FUNCTION ();							      \ +      (ONCE_CONTROL) |= 2;						      \ +    }									      \ +  } while (0) + + +/* Note that for I/O cleanup handling we are using the old-style +   cancel handling.  It does not have to be integrated with C++ snce +   no C++ code is called in the middle.  The old-style handling is +   faster and the support is not going away.  */ +extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *buffer, +                                   void (*routine) (void *), void *arg); +extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *buffer, +                                  int execute); +extern void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *buffer, +                                         void (*routine) (void *), void *arg); +extern void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *buffer, +                                          int execute); + +/* Start critical region with cleanup.  */ +#define __libc_cleanup_region_start(DOIT, FCT, ARG) \ +  { struct _pthread_cleanup_buffer _buffer;				      \ +    int _avail;								      \ +    if (DOIT) {								      \ +      _avail = PTF(_pthread_cleanup_push_defer) != NULL;		      \ +      if (_avail) {							      \ +	PTF(_pthread_cleanup_push_defer) (&_buffer, FCT, ARG);		      \ +      } else {								      \ +	_buffer.__routine = (FCT);					      \ +	_buffer.__arg = (ARG);						      \ +      }									      \ +    } else {								      \ +      _avail = 0;							      \ +    } + +/* End critical region with cleanup.  */ +#define __libc_cleanup_region_end(DOIT) \ +    if (_avail) {							      \ +      PTF(_pthread_cleanup_pop_restore) (&_buffer, DOIT);		      \ +    } else if (DOIT)							      \ +      _buffer.__routine (_buffer.__arg);				      \ +  } + +/* Sometimes we have to exit the block in the middle.  */ +#define __libc_cleanup_end(DOIT) \ +    if (_avail) {							      \ +      PTF(_pthread_cleanup_pop_restore) (&_buffer, DOIT);		      \ +    } else if (DOIT)							      \ +      _buffer.__routine (_buffer.__arg) + + +/* Normal cleanup handling, based on C cleanup attribute.  */ +__extern_inline void +__libc_cleanup_routine (struct __pthread_cleanup_frame *f); + +__extern_inline void +__libc_cleanup_routine (struct __pthread_cleanup_frame *f) +{ +  if (f->__do_it) +    f->__cancel_routine (f->__cancel_arg); +} + +#define __libc_cleanup_push(fct, arg) \ +  do {									      \ +    struct __pthread_cleanup_frame __clframe				      \ +      __attribute__ ((__cleanup__ (__libc_cleanup_routine)))		      \ +      = { .__cancel_routine = (fct), .__cancel_arg = (arg),		      \ +          .__do_it = 1 }; + +#define __libc_cleanup_pop(execute) \ +    __clframe.__do_it = (execute);					      \ +  } while (0) + + +/* Create thread-specific key.  */ +#define __libc_key_create(KEY, DESTRUCTOR) \ +  __libc_ptf_call (__pthread_key_create, (KEY, DESTRUCTOR), 1) + +/* Get thread-specific data.  */ +#define __libc_getspecific(KEY) \ +  __libc_ptf_call (__pthread_getspecific, (KEY), NULL) + +/* Set thread-specific data.  */ +#define __libc_setspecific(KEY, VALUE) \ +  __libc_ptf_call (__pthread_setspecific, (KEY, VALUE), 0) + + +/* Register handlers to execute before and after `fork'.  Note that the +   last parameter is NULL.  The handlers registered by the libc are +   never removed so this is OK.  */ +#define __libc_atfork(PREPARE, PARENT, CHILD) \ +  __register_atfork (PREPARE, PARENT, CHILD, NULL) +extern int __register_atfork (void (*__prepare) (void), +			      void (*__parent) (void), +			      void (*__child) (void), +			      void *__dso_handle); + +/* Functions that are used by this file and are internal to the GNU C +   library.  */ + +extern int __pthread_mutex_init (pthread_mutex_t *__mutex, +				 __const pthread_mutexattr_t *__mutex_attr); + +extern int __pthread_mutex_destroy (pthread_mutex_t *__mutex); + +extern int __pthread_mutex_trylock (pthread_mutex_t *__mutex); + +extern int __pthread_mutex_lock (pthread_mutex_t *__mutex); + +extern int __pthread_mutex_unlock (pthread_mutex_t *__mutex); + +extern int __pthread_mutexattr_init (pthread_mutexattr_t *__attr); + +extern int __pthread_mutexattr_destroy (pthread_mutexattr_t *__attr); + +extern int __pthread_mutexattr_settype (pthread_mutexattr_t *__attr, +					int __kind); + +#ifdef __USE_UNIX98 +extern int __pthread_rwlock_init (pthread_rwlock_t *__rwlock, +				  __const pthread_rwlockattr_t *__attr); + +extern int __pthread_rwlock_destroy (pthread_rwlock_t *__rwlock); + +extern int __pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock); + +extern int __pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock); + +extern int __pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock); + +extern int __pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock); + +extern int __pthread_rwlock_unlock (pthread_rwlock_t *__rwlock); +#endif + +extern int __pthread_key_create (pthread_key_t *__key, +				 void (*__destr_function) (void *)); + +extern int __pthread_setspecific (pthread_key_t __key, +				  __const void *__pointer); + +extern void *__pthread_getspecific (pthread_key_t __key); + +extern int __pthread_once (pthread_once_t *__once_control, +			   void (*__init_routine) (void)); + +extern int __pthread_atfork (void (*__prepare) (void), +			     void (*__parent) (void), +			     void (*__child) (void)); + + + +/* Make the pthread functions weak so that we can elide them from +   single-threaded processes.  */ +#ifndef __NO_WEAK_PTHREAD_ALIASES +# ifdef weak_extern +weak_extern (__pthread_mutex_init) +weak_extern (__pthread_mutex_destroy) +weak_extern (__pthread_mutex_lock) +weak_extern (__pthread_mutex_trylock) +weak_extern (__pthread_mutex_unlock) +weak_extern (__pthread_mutexattr_init) +weak_extern (__pthread_mutexattr_destroy) +weak_extern (__pthread_mutexattr_settype) +weak_extern (__pthread_rwlock_init) +weak_extern (__pthread_rwlock_destroy) +weak_extern (__pthread_rwlock_rdlock) +weak_extern (__pthread_rwlock_tryrdlock) +weak_extern (__pthread_rwlock_wrlock) +weak_extern (__pthread_rwlock_trywrlock) +weak_extern (__pthread_rwlock_unlock) +weak_extern (__pthread_key_create) +weak_extern (__pthread_setspecific) +weak_extern (__pthread_getspecific) +weak_extern (__pthread_once) +weak_extern (__pthread_atfork) +#ifdef SHARED +weak_extern (_pthread_cleanup_push_defer) +weak_extern (_pthread_cleanup_pop_restore) +#endif +weak_extern (pthread_setcancelstate) +# else +#  pragma weak __pthread_mutex_init +#  pragma weak __pthread_mutex_destroy +#  pragma weak __pthread_mutex_lock +#  pragma weak __pthread_mutex_trylock +#  pragma weak __pthread_mutex_unlock +#  pragma weak __pthread_mutexattr_init +#  pragma weak __pthread_mutexattr_destroy +#  pragma weak __pthread_mutexattr_settype +#  pragma weak __pthread_rwlock_destroy +#  pragma weak __pthread_rwlock_rdlock +#  pragma weak __pthread_rwlock_tryrdlock +#  pragma weak __pthread_rwlock_wrlock +#  pragma weak __pthread_rwlock_trywrlock +#  pragma weak __pthread_rwlock_unlock +#  pragma weak __pthread_key_create +#  pragma weak __pthread_setspecific +#  pragma weak __pthread_getspecific +#  pragma weak __pthread_once +#  pragma weak __pthread_atfork +#  pragma weak _pthread_cleanup_push_defer +#  pragma weak _pthread_cleanup_pop_restore +#  pragma weak pthread_setcancelstate +# endif +#endif + +#endif	/* bits/libc-lock.h */ diff --git a/libpthread/nptl/sysdeps/pthread/bits/libc-tsd.h b/libpthread/nptl/sysdeps/pthread/bits/libc-tsd.h new file mode 100644 index 000000000..3f1676b3e --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/bits/libc-tsd.h @@ -0,0 +1,69 @@ +/* libc-internal interface for thread-specific data.  Stub or TLS version. +   Copyright (C) 1998,2001,02 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 _GENERIC_BITS_LIBC_TSD_H +#define _GENERIC_BITS_LIBC_TSD_H 1 + +/* This file defines the following macros for accessing a small fixed +   set of thread-specific `void *' data used only internally by libc. + +   __libc_tsd_define(CLASS, KEY)	-- Define or declare a `void *' datum +                       for KEY.  CLASS can be `static' for +					   keys used in only one source file, +					   empty for global definitions, or +					   `extern' for global declarations. +   __libc_tsd_address(KEY)		-- Return the `void **' pointing to +                       the current thread's datum for KEY. +   __libc_tsd_get(KEY)			-- Return the `void *' datum for KEY. +   __libc_tsd_set(KEY, VALUE)		-- Set the datum for KEY to VALUE. + +   The set of available KEY's will usually be provided as an enum, +   and contains (at least): +		_LIBC_TSD_KEY_MALLOC +		_LIBC_TSD_KEY_DL_ERROR +		_LIBC_TSD_KEY_RPC_VARS +   All uses must be the literal _LIBC_TSD_* name in the __libc_tsd_* macros. +   Some implementations may not provide any enum at all and instead +   using string pasting in the macros.  */ + +#include <tls.h> + +/* When full support for __thread variables is available, this interface is +   just a trivial wrapper for it.  Without TLS, this is the generic/stub +   implementation for wholly single-threaded systems. + +   We don't define an enum for the possible key values, because the KEYs +   translate directly into variables by macro magic.  */ + +#if USE___THREAD +# define __libc_tsd_define(CLASS, KEY)	\ +  CLASS __thread void *__libc_tsd_##KEY attribute_tls_model_ie; + +# define __libc_tsd_address(KEY)	(&__libc_tsd_##KEY) +# define __libc_tsd_get(KEY)		(__libc_tsd_##KEY) +# define __libc_tsd_set(KEY, VALUE)	(__libc_tsd_##KEY = (VALUE)) +#else +# define __libc_tsd_define(CLASS, KEY)	CLASS void *__libc_tsd_##KEY##_data; + +# define __libc_tsd_address(KEY)	(&__libc_tsd_##KEY##_data) +# define __libc_tsd_get(KEY)		(__libc_tsd_##KEY##_data) +# define __libc_tsd_set(KEY, VALUE)	(__libc_tsd_##KEY##_data = (VALUE)) +#endif + +#endif	/* bits/libc-tsd.h */ diff --git a/libpthread/nptl/sysdeps/pthread/bits/sigthread.h b/libpthread/nptl/sysdeps/pthread/bits/sigthread.h new file mode 100644 index 000000000..960bde18a --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/bits/sigthread.h @@ -0,0 +1,38 @@ +/* Signal handling function for threaded programs. +   Copyright (C) 1998, 1999, 2000, 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; 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_SIGTHREAD_H +#define _BITS_SIGTHREAD_H	1 + +#if !defined _SIGNAL_H && !defined _PTHREAD_H +# error "Never include this file directly.  Use <pthread.h> instead" +#endif + +/* Functions for handling signals. */ + +/* Modify the signal mask for the calling thread.  The arguments have +   the same meaning as for sigprocmask(2). */ +extern int pthread_sigmask (int __how, +			    __const __sigset_t *__restrict __newmask, +			    __sigset_t *__restrict __oldmask)__THROW; + +/* Send signal SIGNO to the given thread. */ +extern int pthread_kill (pthread_t __threadid, int __signo) __THROW; + +#endif	/* bits/sigthread.h */ diff --git a/libpthread/nptl/sysdeps/pthread/bits/stdio-lock.h b/libpthread/nptl/sysdeps/pthread/bits/stdio-lock.h new file mode 100644 index 000000000..cd64bc37e --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/bits/stdio-lock.h @@ -0,0 +1,105 @@ +/* Thread package specific definitions of stream lock type.  NPTL version. +   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; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _BITS_STDIO_LOCK_H +#define _BITS_STDIO_LOCK_H 1 + +#include <bits/libc-lock.h> +#include <lowlevellock.h> + + +/* The locking here is very inexpensive, even for inlining.  */ +#define _IO_lock_inexpensive	1 + +typedef struct { int lock; int cnt; void *owner; } _IO_lock_t; + +#define _IO_lock_initializer { LLL_LOCK_INITIALIZER, 0, NULL } + +#define _IO_lock_init(_name) \ +  ((_name) = (_IO_lock_t) _IO_lock_initializer , 0) + +#define _IO_lock_fini(_name) \ +  ((void) 0) + +#define _IO_lock_lock(_name) \ +  do {									      \ +    void *__self = THREAD_SELF;						      \ +    if ((_name).owner != __self)					      \ +      {									      \ +        lll_lock ((_name).lock);					      \ +        (_name).owner = __self;						      \ +      }									      \ +    ++(_name).cnt;							      \ +  } while (0) + +#define _IO_lock_trylock(_name) \ +  ({									      \ +    int __result = 0;							      \ +    void *__self = THREAD_SELF;						      \ +    if ((_name).owner != __self)					      \ +      {									      \ +        if (lll_trylock ((_name).lock) == 0)				      \ +          {								      \ +            (_name).owner = __self;					      \ +            (_name).cnt = 1;						      \ +          }								      \ +        else								      \ +          __result = EBUSY;						      \ +      }									      \ +    else								      \ +      ++(_name).cnt;							      \ +    __result;								      \ +  }) + +#define _IO_lock_unlock(_name) \ +  do {									      \ +    if (--(_name).cnt == 0)						      \ +      {									      \ +        (_name).owner = NULL;						      \ +        lll_unlock ((_name).lock);					      \ +      }									      \ +  } while (0) + + + +#define _IO_cleanup_region_start(_fct, _fp) \ +  __libc_cleanup_region_start (((_fp)->_flags & _IO_USER_LOCK) == 0, _fct, _fp) +#define _IO_cleanup_region_start_noarg(_fct) \ +  __libc_cleanup_region_start (1, _fct, NULL) +#define _IO_cleanup_region_end(_doit) \ +  __libc_cleanup_region_end (_doit) + +#if defined _LIBC && !defined NOT_IN_libc + +# ifdef __EXCEPTIONS +#  define _IO_acquire_lock(_fp) \ +  do {									      \ +    _IO_FILE *_IO_acquire_lock_file					      \ +	__attribute__((cleanup (_IO_acquire_lock_fct)))			      \ +	= (_fp);							      \ +    _IO_flockfile (_IO_acquire_lock_file); + +# else +#  define _IO_acquire_lock(_fp) _IO_acquire_lock_needs_exceptions_enabled +# endif +# define _IO_release_lock(_fp) ; } while (0) + +#endif + +#endif /* bits/stdio-lock.h */ diff --git a/libpthread/nptl/sysdeps/pthread/createthread.c b/libpthread/nptl/sysdeps/pthread/createthread.c new file mode 100644 index 000000000..88ffe09d3 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/createthread.c @@ -0,0 +1,255 @@ +/* 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 <sched.h> +#include <setjmp.h> +#include <signal.h> +#include <stdlib.h> +#include <atomic.h> +#include <ldsodefs.h> +#include <tls.h> + +#include <bits/kernel-features.h> + + +#define CLONE_SIGNAL    	(CLONE_SIGHAND | CLONE_THREAD) + +/* Unless otherwise specified, the thread "register" is going to be +   initialized with a pointer to the TCB.  */ +#ifndef TLS_VALUE +# define TLS_VALUE pd +#endif + +#ifndef ARCH_CLONE +# define ARCH_CLONE __clone +#endif + + +#ifndef TLS_MULTIPLE_THREADS_IN_TCB +/* Pointer to the corresponding variable in libc.  */ +int *__libc_multiple_threads_ptr attribute_hidden; +#endif + + +static int +do_clone (struct pthread *pd, const struct pthread_attr *attr, +	  int clone_flags, int (*fct) (void *), STACK_VARIABLES_PARMS, +	  int stopped) +{ +#ifdef PREPARE_CREATE +  PREPARE_CREATE; +#endif + +  if (stopped) +    /* We Make sure the thread does not run far by forcing it to get a +       lock.  We lock it here too so that the new thread cannot continue +       until we tell it to.  */ +    lll_lock (pd->lock); + +  /* One more thread.  We cannot have the thread do this itself, since it +     might exist but not have been scheduled yet by the time we've returned +     and need to check the value to behave correctly.  We must do it before +     creating the thread, in case it does get scheduled first and then +     might mistakenly think it was the only thread.  In the failure case, +     we momentarily store a false value; this doesn't matter because there +     is no kosher thing a signal handler interrupting us right here can do +     that cares whether the thread count is correct.  */ +  atomic_increment (&__nptl_nthreads); + +  if (ARCH_CLONE (fct, STACK_VARIABLES_ARGS, clone_flags, +		  pd, &pd->tid, TLS_VALUE, &pd->tid) == -1) +    { +      atomic_decrement (&__nptl_nthreads); /* Oops, we lied for a second.  */ + +      /* Failed.  If the thread is detached, remove the TCB here since +	 the caller cannot do this.  The caller remembered the thread +	 as detached and cannot reverify that it is not since it must +	 not access the thread descriptor again.  */ +      if (IS_DETACHED (pd)) +	__deallocate_stack (pd); + +      return errno; +    } + +  /* Now we have the possibility to set scheduling parameters etc.  */ +  if (__builtin_expect (stopped != 0, 0)) +    { +      INTERNAL_SYSCALL_DECL (err); +      int res = 0; + +      /* Set the affinity mask if necessary.  */ +      if (attr->cpuset != NULL) +	{ +	  res = INTERNAL_SYSCALL (sched_setaffinity, err, 3, pd->tid, +				  sizeof (cpu_set_t), attr->cpuset); + +	  if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0)) +	    { +	      /* The operation failed.  We have to kill the thread.  First +		 send it the cancellation signal.  */ +	      INTERNAL_SYSCALL_DECL (err2); +	    err_out: +#if __ASSUME_TGKILL +	      (void) INTERNAL_SYSCALL (tgkill, err2, 3, +				       THREAD_GETMEM (THREAD_SELF, pid), +				       pd->tid, SIGCANCEL); +#else +	      (void) INTERNAL_SYSCALL (tkill, err2, 2, pd->tid, SIGCANCEL); +#endif + +	      return (INTERNAL_SYSCALL_ERROR_P (res, err) +		      ? INTERNAL_SYSCALL_ERRNO (res, err) +		      : 0); +	    } +	} + +      /* Set the scheduling parameters.  */ +      if ((attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0) +	{ +	  res = INTERNAL_SYSCALL (sched_setscheduler, err, 3, pd->tid, +				  pd->schedpolicy, &pd->schedparam); + +	  if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0)) +	    goto err_out; +	} +    } + +  /* We now have for sure more than one thread.  The main thread might +     not yet have the flag set.  No need to set the global variable +     again if this is what we use.  */ +  THREAD_SETMEM (THREAD_SELF, header.multiple_threads, 1); + +  return 0; +} + + +static int +create_thread (struct pthread *pd, const struct pthread_attr *attr, +	       STACK_VARIABLES_PARMS) +{ +#ifdef TLS_TCB_AT_TP +  assert (pd->header.tcb != NULL); +#endif + +  /* We rely heavily on various flags the CLONE function understands: + +     CLONE_VM, CLONE_FS, CLONE_FILES +	These flags select semantics with shared address space and +	file descriptors according to what POSIX requires. + +     CLONE_SIGNAL +	This flag selects the POSIX signal semantics. + +     CLONE_SETTLS +	The sixth parameter to CLONE determines the TLS area for the +	new thread. + +     CLONE_PARENT_SETTID +	The kernels writes the thread ID of the newly created thread +	into the location pointed to by the fifth parameters to CLONE. + +	Note that it would be semantically equivalent to use +	CLONE_CHILD_SETTID but it is be more expensive in the kernel. + +     CLONE_CHILD_CLEARTID +	The kernels clears the thread ID of a thread that has called +	sys_exit() in the location pointed to by the seventh parameter +	to CLONE. + +     CLONE_DETACHED +	No signal is generated if the thread exists and it is +	automatically reaped. + +     The termination signal is chosen to be zero which means no signal +     is sent.  */ +  int clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL +		     | CLONE_SETTLS | CLONE_PARENT_SETTID +		     | CLONE_CHILD_CLEARTID | CLONE_SYSVSEM +#if __ASSUME_NO_CLONE_DETACHED == 0 +		     | CLONE_DETACHED +#endif +		     | 0); + +  if (__builtin_expect (THREAD_GETMEM (THREAD_SELF, report_events), 0)) +    { +      /* The parent thread is supposed to report events.  Check whether +	 the TD_CREATE event is needed, too.  */ +      const int _idx = __td_eventword (TD_CREATE); +      const uint32_t _mask = __td_eventmask (TD_CREATE); + +      if ((_mask & (__nptl_threads_events.event_bits[_idx] +		    | pd->eventbuf.eventmask.event_bits[_idx])) != 0) +	{ +	  /* We always must have the thread start stopped.  */ +	  pd->stopped_start = true; + +	  /* Create the thread.  We always create the thread stopped +	     so that it does not get far before we tell the debugger.  */ +	  int res = do_clone (pd, attr, clone_flags, start_thread, +			      STACK_VARIABLES_ARGS, 1); +	  if (res == 0) +	    { +	      /* Now fill in the information about the new thread in +		 the newly created thread's data structure.  We cannot let +		 the new thread do this since we don't know whether it was +		 already scheduled when we send the event.  */ +	      pd->eventbuf.eventnum = TD_CREATE; +	      pd->eventbuf.eventdata = pd; + +	      /* Enqueue the descriptor.  */ +	      do +		pd->nextevent = __nptl_last_event; +	      while (atomic_compare_and_exchange_bool_acq (&__nptl_last_event, +							   pd, pd->nextevent) +		     != 0); + +	      /* Now call the function which signals the event.  */ +	      __nptl_create_event (); + +	      /* And finally restart the new thread.  */ +	      lll_unlock (pd->lock); +	    } + +	  return res; +	} +    } + +#ifdef NEED_DL_SYSINFO +  assert (THREAD_SELF_SYSINFO == THREAD_SYSINFO (pd)); +#endif + +  /* Determine whether the newly created threads has to be started +     stopped since we have to set the scheduling parameters or set the +     affinity.  */ +  bool stopped = false; +  if (attr != NULL && (attr->cpuset != NULL +		       || (attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0)) +    stopped = true; +  pd->stopped_start = stopped; + +  /* Actually create the thread.  */ +  int res = do_clone (pd, attr, clone_flags, start_thread, +		      STACK_VARIABLES_ARGS, stopped); + +  if (res == 0 && stopped) +    /* And finally restart the new thread.  */ +    lll_unlock (pd->lock); + +  return res; +} diff --git a/libpthread/nptl/sysdeps/pthread/defs.awk b/libpthread/nptl/sysdeps/pthread/defs.awk new file mode 100644 index 000000000..d41d57bd7 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/defs.awk @@ -0,0 +1,24 @@ +/^[ 	]*\.endp/	 { need_endp = 1 } +/^[ 	]*\.end/	 { need_end = 1 } +/^[ 	]*\.align/ { if($2 > max) max = $2; } + +END { +    if(need_endp) +    { +	print "#define END_INIT .endp _init"; +	print "#define END_FINI .endp _fini"; +    } else if(need_end) +    { +	print "#define END_INIT .end _init"; +	print "#define END_FINI .end _fini"; +    } +    else +    { +	print "#define END_INIT"; +	print "#define END_FINI"; +    } +    if(max) +	print "#define ALIGN .align", max; +    else +	print "#define ALIGN"; +} diff --git a/libpthread/nptl/sysdeps/pthread/librt-cancellation.c b/libpthread/nptl/sysdeps/pthread/librt-cancellation.c new file mode 100644 index 000000000..753a2d831 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/librt-cancellation.c @@ -0,0 +1,108 @@ +/* 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 <signal.h> +#include <stdlib.h> +#include "pthreadP.h" +#include "atomic.h" + + +#ifdef IS_IN_librt +/* The next two functions are similar to pthread_setcanceltype() but +   more specialized for the use in the cancelable functions like write(). +   They do not need to check parameters etc.  */ +int +attribute_hidden +__librt_enable_asynccancel (void) +{ +  struct pthread *self = THREAD_SELF; +  int oldval = THREAD_GETMEM (self, cancelhandling); + +  while (1) +    { +      int newval = oldval | CANCELTYPE_BITMASK; + +      if (__builtin_expect ((oldval & CANCELED_BITMASK) != 0, 0)) +	{ +	  /* If we are already exiting or if PTHREAD_CANCEL_DISABLED, +	     stop right here.  */ +	  if ((oldval & (EXITING_BITMASK | CANCELSTATE_BITMASK)) != 0) +	    break; + +	  int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, +						  newval, oldval); +	  if (__builtin_expect (curval != oldval, 0)) +	    { +	      /* Somebody else modified the word, try again.  */ +	      oldval = curval; +	      continue; +	    } + +	  THREAD_SETMEM (self, result, PTHREAD_CANCELED); + +	  __do_cancel (); + +	  /* NOTREACHED */ +	} + +      int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, +					      oldval); +      if (__builtin_expect (curval == oldval, 1)) +	break; + +      /* Prepare the next round.  */ +      oldval = curval; +    } + +  return oldval; +} + + +void +internal_function attribute_hidden +__librt_disable_asynccancel (int oldtype) +{ +  /* If asynchronous cancellation was enabled before we do not have +     anything to do.  */ +  if (oldtype & CANCELTYPE_BITMASK) +    return; + +  struct pthread *self = THREAD_SELF; +  int oldval = THREAD_GETMEM (self, cancelhandling); + +  while (1) +    { +      int newval = oldval & ~CANCELTYPE_BITMASK; + +      if (newval == oldval) +	break; + +      int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, +					      oldval); +      if (__builtin_expect (curval == oldval, 1)) +	break; + +      /* Prepare the next round.  */ +      oldval = curval; +    } +} + + +#endif diff --git a/libpthread/nptl/sysdeps/pthread/list.h b/libpthread/nptl/sysdeps/pthread/list.h new file mode 100644 index 000000000..43186a2d5 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/list.h @@ -0,0 +1,114 @@ +/* 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 _LIST_H +#define _LIST_H	1 + +/* The definitions of this file are adopted from those which can be +   found in the Linux kernel headers to enable people familiar with +   the latter find their way in these sources as well.  */ + + +/* Basic type for the double-link list.  */ +typedef struct list_head +{ +  struct list_head *next; +  struct list_head *prev; +} list_t; + + +/* Define a variable with the head and tail of the list.  */ +#define LIST_HEAD(name) \ +  list_t name = { &(name), &(name) } + +/* Initialize a new list head.  */ +#define INIT_LIST_HEAD(ptr) \ +  (ptr)->next = (ptr)->prev = (ptr) + + +/* Add new element at the head of the list.  */ +static inline void +list_add (list_t *newp, list_t *head) +{ +  head->next->prev = newp; +  newp->next = head->next; +  newp->prev = head; +  head->next = newp; +} + + +/* Add new element at the tail of the list.  */ +static inline void +list_add_tail (list_t *newp, list_t *head) +{ +  head->prev->next = newp; +  newp->next = head; +  newp->prev = head->prev; +  head->prev = newp; +} + + +/* Remove element from list.  */ +static inline void +list_del (list_t *elem) +{ +  elem->next->prev = elem->prev; +  elem->prev->next = elem->next; +} + + +/* Join two lists.  */ +static inline void +list_splice (list_t *add, list_t *head) +{ +  /* Do nothing if the list which gets added is empty.  */ +  if (add != add->next) +    { +      add->next->prev = head; +      add->prev->next = head->next; +      head->next->prev = add->prev; +      head->next = add->next; +    } +} + + +/* Get typed element from list at a given position.  */ +#define list_entry(ptr, type, member) \ +  ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member))) + + + +/* Iterate forward over the elements of the list.  */ +#define list_for_each(pos, head) \ +  for (pos = (head)->next; pos != (head); pos = pos->next) + + +/* Iterate forward over the elements of the list.  */ +#define list_for_each_prev(pos, head) \ +  for (pos = (head)->prev; pos != (head); pos = pos->prev) + + +/* Iterate backwards over the elements list.  The list elements can be +   removed from the list while doing this.  */ +#define list_for_each_prev_safe(pos, p, head) \ +  for (pos = (head)->prev, p = pos->prev; \ +       pos != (head); \ +       pos = p, p = pos->prev) + +#endif	/* list.h */ diff --git a/libpthread/nptl/sysdeps/pthread/malloc-machine.h b/libpthread/nptl/sysdeps/pthread/malloc-machine.h new file mode 100644 index 000000000..efab230aa --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/malloc-machine.h @@ -0,0 +1,62 @@ +/* Basic platform-independent macro definitions for mutexes, +   thread-specific data and parameters for malloc. +   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 _MALLOC_MACHINE_H +#define _MALLOC_MACHINE_H + +#undef thread_atfork_static + +#include <atomic.h> +#include <bits/libc-lock.h> + +__libc_lock_define (typedef, mutex_t) + +#define mutex_init(m)		__libc_lock_init (*(m)) +#define mutex_lock(m)		__libc_lock_lock (*(m)) +#define mutex_trylock(m)	__libc_lock_trylock (*(m)) +#define mutex_unlock(m)		__libc_lock_unlock (*(m)) + +/* This is defined by newer gcc version unique for each module.  */ +extern void *__dso_handle __attribute__ ((__weak__)); + +#include <fork.h> + +#ifdef SHARED +# define thread_atfork(prepare, parent, child) \ +   __register_atfork (prepare, parent, child, __dso_handle) +#else +# define thread_atfork(prepare, parent, child) \ +   __register_atfork (prepare, parent, child,				      \ +		      &__dso_handle == NULL ? NULL : __dso_handle) +#endif + +/* thread specific data for glibc */ + +#include <bits/libc-tsd.h> + +typedef int tsd_key_t[1];	/* no key data structure, libc magic does it */ +__libc_tsd_define (static, MALLOC)	/* declaration/common definition */ +#define tsd_key_create(key, destr)	((void) (key)) +#define tsd_setspecific(key, data)	__libc_tsd_set (MALLOC, (data)) +#define tsd_getspecific(key, vptr)	((vptr) = __libc_tsd_get (MALLOC)) + +#include <sysdeps/generic/malloc-machine.h> + +#endif /* !defined(_MALLOC_MACHINE_H) */ diff --git a/libpthread/nptl/sysdeps/pthread/posix-timer.h b/libpthread/nptl/sysdeps/pthread/posix-timer.h new file mode 100644 index 000000000..8b4cbc8cd --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/posix-timer.h @@ -0,0 +1,197 @@ +/* Definitions for POSIX timer implementation on top of NPTL. +   Copyright (C) 2000, 2002, 2003, 2004 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General 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 <limits.h> +#include <signal.h> + +/* Double linked list.  */ +struct list_links +{ +  struct list_links *next; +  struct list_links *prev; +}; + + +/* Forward declaration.  */ +struct timer_node; + + +/* Definitions for an internal thread of the POSIX timer implementation.  */ +struct thread_node +{ +  struct list_links links; +  pthread_attr_t attr; +  pthread_t id; +  unsigned int exists; +  struct list_links timer_queue; +  pthread_cond_t cond; +  struct timer_node *current_timer; +  pthread_t captured; +  clockid_t clock_id; +}; + + +/* Internal representation of a timer.  */ +struct timer_node +{ +  struct list_links links; +  struct sigevent event; +  clockid_t clock; +  struct itimerspec value; +  struct timespec expirytime; +  pthread_attr_t attr; +  unsigned int abstime; +  unsigned int armed; +  enum { +    TIMER_FREE, TIMER_INUSE, TIMER_DELETED +  } inuse; +  struct thread_node *thread; +  pid_t creator_pid; +  int refcount; +  int overrun_count; +}; + + +/* The limit is not published if we are compiled with kernel timer support. +   But we still compiled in this implementation with its limit unless built +   to require the kernel support.  */ +#ifndef TIMER_MAX +# define TIMER_MAX 256 +#endif + +/* Static array with the structures for all the timers.  */ +extern struct timer_node __timer_array[TIMER_MAX]; + +/* Global lock to protect operation on the lists.  */ +extern pthread_mutex_t __timer_mutex; + +/* Variable to protext initialization.  */ +extern pthread_once_t __timer_init_once_control; + +/* Nonzero if initialization of timer implementation failed.  */ +extern int __timer_init_failed; + +/* Node for the thread used to deliver signals.  */ +extern struct thread_node __timer_signal_thread_rclk; + + +/* Return pointer to timer structure corresponding to ID.  */ +#define timer_id2ptr(timerid) ((struct timer_node *) timerid) +#define timer_ptr2id(timerid) ((void *) timerid) + +/* Check whether timer is valid; global mutex must be held. */ +static inline int +timer_valid (struct timer_node *timer) +{ +  return timer && timer->inuse == TIMER_INUSE; +} + +/* Timer refcount functions; need global mutex. */ +extern void __timer_dealloc (struct timer_node *timer); + +static inline void +timer_addref (struct timer_node *timer) +{ +  timer->refcount++; +} + +static inline void +timer_delref (struct timer_node *timer) +{ +  if (--timer->refcount == 0) +    __timer_dealloc (timer); +} + +/* Timespec helper routines.  */ +static inline int +__attribute ((always_inline)) +timespec_compare (const struct timespec *left, const struct timespec *right) +{ +  if (left->tv_sec < right->tv_sec) +    return -1; +  if (left->tv_sec > right->tv_sec) +    return 1; + +  if (left->tv_nsec < right->tv_nsec) +    return -1; +  if (left->tv_nsec > right->tv_nsec) +    return 1; + +  return 0; +} + +static inline void +timespec_add (struct timespec *sum, const struct timespec *left, +	      const struct timespec *right) +{ +  sum->tv_sec = left->tv_sec + right->tv_sec; +  sum->tv_nsec = left->tv_nsec + right->tv_nsec; + +  if (sum->tv_nsec >= 1000000000) +    { +      ++sum->tv_sec; +      sum->tv_nsec -= 1000000000; +    } +} + +static inline void +timespec_sub (struct timespec *diff, const struct timespec *left, +	      const struct timespec *right) +{ +  diff->tv_sec = left->tv_sec - right->tv_sec; +  diff->tv_nsec = left->tv_nsec - right->tv_nsec; + +  if (diff->tv_nsec < 0) +    { +      --diff->tv_sec; +      diff->tv_nsec += 1000000000; +    } +} + + +/* We need one of the list functions in the other modules.  */ +static inline void +list_unlink_ip (struct list_links *list) +{ +  struct list_links *lnext = list->next, *lprev = list->prev; + +  lnext->prev = lprev; +  lprev->next = lnext; + +  /* The suffix ip means idempotent; list_unlink_ip can be called +   * two or more times on the same node. +   */ + +  list->next = list; +  list->prev = list; +} + + +/* Functions in the helper file.  */ +extern void __timer_mutex_cancel_handler (void *arg); +extern void __timer_init_once (void); +extern struct timer_node *__timer_alloc (void); +extern int __timer_thread_start (struct thread_node *thread); +extern struct thread_node *__timer_thread_find_matching (const pthread_attr_t *desired_attr, clockid_t); +extern struct thread_node *__timer_thread_alloc (const pthread_attr_t *desired_attr, clockid_t); +extern void __timer_thread_dealloc (struct thread_node *thread); +extern int __timer_thread_queue_timer (struct thread_node *thread, +				       struct timer_node *insert); +extern void __timer_thread_wakeup (struct thread_node *thread); diff --git a/libpthread/nptl/sysdeps/pthread/pt-initfini.c b/libpthread/nptl/sysdeps/pthread/pt-initfini.c new file mode 100644 index 000000000..5955a7efc --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pt-initfini.c @@ -0,0 +1,125 @@ +/* Special .init and .fini section support.  Linuxthread version. +   Copyright (C) 1995,1996,1997,2000,2001,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 of the License, or (at your option) any later version. + +   In addition to the permissions in the GNU Lesser 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 Lesser General 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, 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. */ + +#include <stdlib.h> + +/* We use embedded asm for .section unconditionally, as this makes it +   easier to insert the necessary directives into crtn.S. */ +#define SECTION(x) __asm__ (".section " x ) + +/* Embed an #include to pull in the alignment and .end directives. */ +asm ("\n#include \"defs.h\""); + +/* The initial common code ends here. */ +asm ("\n/*@HEADER_ENDS*/"); + +/* To determine whether we need .end and .align: */ +asm ("\n/*@TESTS_BEGIN*/"); +extern void dummy (void (*foo) (void)); +void +dummy (void (*foo) (void)) +{ +  if (foo) +    (*foo) (); +} +asm ("\n/*@TESTS_END*/"); + +/* The beginning of _init:  */ +asm ("\n/*@_init_PROLOG_BEGINS*/"); + +static void +call_initialize_minimal (void) +{ +  extern void __pthread_initialize_minimal_internal (void) +    __attribute ((visibility ("hidden"))); + +  __pthread_initialize_minimal_internal (); +} + +SECTION (".init"); +extern void _init (void); +void +_init (void) +{ +  /* The very first thing we must do is to set up the registers.  */ +  call_initialize_minimal (); + +  asm ("ALIGN"); +  asm("END_INIT"); +  /* Now the epilog. */ +  asm ("\n/*@_init_PROLOG_ENDS*/"); +  asm ("\n/*@_init_EPILOG_BEGINS*/"); +  SECTION(".init"); +} +asm ("END_INIT"); + +/* End of the _init epilog, beginning of the _fini prolog. */ +asm ("\n/*@_init_EPILOG_ENDS*/"); +asm ("\n/*@_fini_PROLOG_BEGINS*/"); + +SECTION (".fini"); +extern void _fini (void); +void +_fini (void) +{ + +  /* End of the _fini prolog. */ +  asm ("ALIGN"); +  asm ("END_FINI"); +  asm ("\n/*@_fini_PROLOG_ENDS*/"); + +  { +    /* Let GCC know that _fini is not a leaf function by having a dummy +       function call here.  We arrange for this call to be omitted from +       either crt file.  */ +    extern void i_am_not_a_leaf (void); +    i_am_not_a_leaf (); +  } + +  /* Beginning of the _fini epilog. */ +  asm ("\n/*@_fini_EPILOG_BEGINS*/"); +  SECTION (".fini"); +} +asm ("END_FINI"); + +/* End of the _fini epilog.  Any further generated assembly (e.g. .ident) +   is shared between both crt files. */ +asm ("\n/*@_fini_EPILOG_ENDS*/"); +asm ("\n/*@TRAILER_BEGINS*/"); + +/* End of file. */ diff --git a/libpthread/nptl/sysdeps/pthread/pt-longjmp.c b/libpthread/nptl/sysdeps/pthread/pt-longjmp.c new file mode 100644 index 000000000..b4106fdba --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pt-longjmp.c @@ -0,0 +1,31 @@ +/* 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 "pthreadP.h" + +extern void __libc_longjmp (sigjmp_buf env, int val) +	__attribute__ ((noreturn)); +void +longjmp (jmp_buf env, int val) +{ +  __libc_longjmp (env, val); +} +weak_alias (longjmp, siglongjmp) diff --git a/libpthread/nptl/sysdeps/pthread/pthread-functions.h b/libpthread/nptl/sysdeps/pthread/pthread-functions.h new file mode 100644 index 000000000..813d55621 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread-functions.h @@ -0,0 +1,107 @@ +/* Copyright (C) 2003, 2004, 2005 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.  */ + +#ifndef _PTHREAD_FUNCTIONS_H +#define _PTHREAD_FUNCTIONS_H	1 + +#include <pthread.h> +#include <setjmp.h> +#include <internaltypes.h> + +struct xid_command; + +/* Data type shared with libc.  The libc uses it to pass on calls to +   the thread functions.  */ +struct pthread_functions +{ +  int (*ptr_pthread_attr_destroy) (pthread_attr_t *); +  int (*ptr___pthread_attr_init_2_0) (pthread_attr_t *); +  int (*ptr___pthread_attr_init_2_1) (pthread_attr_t *); +  int (*ptr_pthread_attr_getdetachstate) (const pthread_attr_t *, int *); +  int (*ptr_pthread_attr_setdetachstate) (pthread_attr_t *, int); +  int (*ptr_pthread_attr_getinheritsched) (const pthread_attr_t *, int *); +  int (*ptr_pthread_attr_setinheritsched) (pthread_attr_t *, int); +  int (*ptr_pthread_attr_getschedparam) (const pthread_attr_t *, +					 struct sched_param *); +  int (*ptr_pthread_attr_setschedparam) (pthread_attr_t *, +					 const struct sched_param *); +  int (*ptr_pthread_attr_getschedpolicy) (const pthread_attr_t *, int *); +  int (*ptr_pthread_attr_setschedpolicy) (pthread_attr_t *, int); +  int (*ptr_pthread_attr_getscope) (const pthread_attr_t *, int *); +  int (*ptr_pthread_attr_setscope) (pthread_attr_t *, int); +  int (*ptr_pthread_condattr_destroy) (pthread_condattr_t *); +  int (*ptr_pthread_condattr_init) (pthread_condattr_t *); +  int (*ptr___pthread_cond_broadcast) (pthread_cond_t *); +  int (*ptr___pthread_cond_destroy) (pthread_cond_t *); +  int (*ptr___pthread_cond_init) (pthread_cond_t *, +				  const pthread_condattr_t *); +  int (*ptr___pthread_cond_signal) (pthread_cond_t *); +  int (*ptr___pthread_cond_wait) (pthread_cond_t *, pthread_mutex_t *); +  int (*ptr___pthread_cond_timedwait) (pthread_cond_t *, pthread_mutex_t *, +				       const struct timespec *); +  int (*ptr___pthread_cond_broadcast_2_0) (pthread_cond_2_0_t *); +  int (*ptr___pthread_cond_destroy_2_0) (pthread_cond_2_0_t *); +  int (*ptr___pthread_cond_init_2_0) (pthread_cond_2_0_t *, +				      const pthread_condattr_t *); +  int (*ptr___pthread_cond_signal_2_0) (pthread_cond_2_0_t *); +  int (*ptr___pthread_cond_wait_2_0) (pthread_cond_2_0_t *, pthread_mutex_t *); +  int (*ptr___pthread_cond_timedwait_2_0) (pthread_cond_2_0_t *, +					   pthread_mutex_t *, +					   const struct timespec *); +  int (*ptr_pthread_equal) (pthread_t, pthread_t); +  void (*ptr___pthread_exit) (void *); +  int (*ptr_pthread_getschedparam) (pthread_t, int *, struct sched_param *); +  int (*ptr_pthread_setschedparam) (pthread_t, int, +				    const struct sched_param *); +  int (*ptr_pthread_mutex_destroy) (pthread_mutex_t *); +  int (*ptr_pthread_mutex_init) (pthread_mutex_t *, +				 const pthread_mutexattr_t *); +  int (*ptr_pthread_mutex_trylock) (pthread_mutex_t *); +  int (*ptr_pthread_mutex_lock) (pthread_mutex_t *); +  int (*ptr_pthread_mutex_unlock) (pthread_mutex_t *); +  int (*ptr_pthread_mutexattr_init) (pthread_mutexattr_t *attr); +  int (*ptr_pthread_mutexattr_destroy) (pthread_mutexattr_t *attr); +  int (*ptr_pthread_mutexattr_settype) (pthread_mutexattr_t *attr, int kind); +  pthread_t (*ptr_pthread_self) (void); +  int (*ptr_pthread_setcancelstate) (int, int *); +  int (*ptr_pthread_setcanceltype) (int, int *); +  void (*ptr___pthread_cleanup_upto) (__jmp_buf, char *); +  int (*ptr___pthread_once) (pthread_once_t *, void (*) (void)); +  int (*ptr___pthread_rwlock_rdlock) (pthread_rwlock_t *); +  int (*ptr___pthread_rwlock_wrlock) (pthread_rwlock_t *); +  int (*ptr___pthread_rwlock_unlock) (pthread_rwlock_t *); +  int (*ptr___pthread_key_create) (pthread_key_t *, void (*) (void *)); +  void *(*ptr___pthread_getspecific) (pthread_key_t); +  int (*ptr___pthread_setspecific) (pthread_key_t, const void *); +  void (*ptr__pthread_cleanup_push_defer) (struct _pthread_cleanup_buffer *, +					   void (*) (void *), void *); +  void (*ptr__pthread_cleanup_pop_restore) (struct _pthread_cleanup_buffer *, +					    int); +#define HAVE_PTR_NTHREADS +  unsigned int *ptr_nthreads; +  void (*ptr___pthread_unwind) (__pthread_unwind_buf_t *) +       __attribute ((noreturn)) __cleanup_fct_attribute; +  void (*ptr__nptl_deallocate_tsd) (void); +  int (*ptr__nptl_setxid) (struct xid_command *); +}; + +/* Variable in libc.so.  */ +extern struct pthread_functions __libc_pthread_functions attribute_hidden; + +#endif	/* pthread-functions.h */ diff --git a/libpthread/nptl/sysdeps/pthread/pthread.h b/libpthread/nptl/sysdeps/pthread/pthread.h new file mode 100644 index 000000000..c4bfc0e81 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread.h @@ -0,0 +1,976 @@ +/* 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.  */ + +#ifndef _PTHREAD_H +#define _PTHREAD_H	1 + +#include <features.h> +#include <sched.h> +#include <time.h> + +#define __need_sigset_t +#include <signal.h> +#include <bits/pthreadtypes.h> +#include <bits/setjmp.h> +#include <bits/wordsize.h> +#if defined _LIBC && ( defined IS_IN_libc || defined NOT_IN_libc ) +#include <bits/uClibc_pthread.h> +#endif + + +/* Detach state.  */ +enum +{ +  PTHREAD_CREATE_JOINABLE, +#define PTHREAD_CREATE_JOINABLE	PTHREAD_CREATE_JOINABLE +  PTHREAD_CREATE_DETACHED +#define PTHREAD_CREATE_DETACHED	PTHREAD_CREATE_DETACHED +}; + + +/* Mutex types.  */ +enum +{ +  PTHREAD_MUTEX_TIMED_NP, +  PTHREAD_MUTEX_RECURSIVE_NP, +  PTHREAD_MUTEX_ERRORCHECK_NP, +  PTHREAD_MUTEX_ADAPTIVE_NP +#ifdef __USE_UNIX98 +  , +  PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_TIMED_NP, +  PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP, +  PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP, +  PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL +#endif +#ifdef __USE_GNU +  /* For compatibility.  */ +  , PTHREAD_MUTEX_FAST_NP = PTHREAD_MUTEX_TIMED_NP +#endif +}; + +/* Mutex initializers.  */ +#if __WORDSIZE == 64 +# define PTHREAD_MUTEX_INITIALIZER \ +  { { 0, 0, 0, 0, 0, 0, { 0, 0 } } } +# ifdef __USE_GNU +#  define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \ +  { { 0, 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, 0, { 0, 0 } } } +#  define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \ +  { { 0, 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, 0, { 0, 0 } } } +#  define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \ +  { { 0, 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, 0, { 0, 0 } } } +# endif +#else +# define PTHREAD_MUTEX_INITIALIZER \ +  { { 0, 0, 0, 0, 0, { 0 } } } +# ifdef __USE_GNU +#  define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \ +  { { 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, 0, { 0 } } } +#  define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \ +  { { 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, 0, { 0 } } } +#  define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \ +  { { 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, 0, { 0 } } } +# endif +#endif + +/* Read-write lock types.  */ +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +enum +{ +  PTHREAD_RWLOCK_PREFER_READER_NP, +  PTHREAD_RWLOCK_PREFER_WRITER_NP, +  PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, +  PTHREAD_RWLOCK_DEFAULT_NP = PTHREAD_RWLOCK_PREFER_READER_NP +}; + +/* Read-write lock initializers.  */ +# if __WORDSIZE == 64 +#  define PTHREAD_RWLOCK_INITIALIZER \ +  { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } +# else +#  define PTHREAD_RWLOCK_INITIALIZER \ +  { { 0, 0, 0, 0, 0, 0, 0, 0 } } +# endif +# ifdef __USE_GNU +#  if __WORDSIZE == 64 +#   define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \ +  { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,					      \ +      PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP } } +#  else +#   define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \ +  { { 0, 0, 0, 0, 0, 0, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, 0 } } +#  endif +# endif +#endif  /* Unix98 or XOpen2K */ + + +/* Scheduler inheritance.  */ +enum +{ +  PTHREAD_INHERIT_SCHED, +#define PTHREAD_INHERIT_SCHED   PTHREAD_INHERIT_SCHED +  PTHREAD_EXPLICIT_SCHED +#define PTHREAD_EXPLICIT_SCHED  PTHREAD_EXPLICIT_SCHED +}; + + +/* Scope handling.  */ +enum +{ +  PTHREAD_SCOPE_SYSTEM, +#define PTHREAD_SCOPE_SYSTEM    PTHREAD_SCOPE_SYSTEM +  PTHREAD_SCOPE_PROCESS +#define PTHREAD_SCOPE_PROCESS   PTHREAD_SCOPE_PROCESS +}; + + +/* Process shared or private flag.  */ +enum +{ +  PTHREAD_PROCESS_PRIVATE, +#define PTHREAD_PROCESS_PRIVATE PTHREAD_PROCESS_PRIVATE +  PTHREAD_PROCESS_SHARED +#define PTHREAD_PROCESS_SHARED  PTHREAD_PROCESS_SHARED +}; + + + +/* Conditional variable handling.  */ +#define PTHREAD_COND_INITIALIZER { { 0, 0, 0, 0, 0, (void *) 0, 0, 0 } } + + +/* Cleanup buffers */ +struct _pthread_cleanup_buffer +{ +  void (*__routine) (void *);             /* Function to call.  */ +  void *__arg;                            /* Its argument.  */ +  int __canceltype;                       /* Saved cancellation type. */ +  struct _pthread_cleanup_buffer *__prev; /* Chaining of cleanup functions.  */ +}; + +/* Cancellation */ +enum +{ +  PTHREAD_CANCEL_ENABLE, +#define PTHREAD_CANCEL_ENABLE   PTHREAD_CANCEL_ENABLE +  PTHREAD_CANCEL_DISABLE +#define PTHREAD_CANCEL_DISABLE  PTHREAD_CANCEL_DISABLE +}; +enum +{ +  PTHREAD_CANCEL_DEFERRED, +#define PTHREAD_CANCEL_DEFERRED	PTHREAD_CANCEL_DEFERRED +  PTHREAD_CANCEL_ASYNCHRONOUS +#define PTHREAD_CANCEL_ASYNCHRONOUS	PTHREAD_CANCEL_ASYNCHRONOUS +}; +#define PTHREAD_CANCELED ((void *) -1) + + +/* Single execution handling.  */ +#define PTHREAD_ONCE_INIT 0 + + +#ifdef __USE_XOPEN2K +/* Value returned by 'pthread_barrier_wait' for one of the threads after +   the required number of threads have called this function. +   -1 is distinct from 0 and all errno constants */ +# define PTHREAD_BARRIER_SERIAL_THREAD -1 +#endif + + +__BEGIN_DECLS + +/* Create a new thread, starting with execution of START-ROUTINE +   getting passed ARG.  Creation attributed come from ATTR.  The new +   handle is stored in *NEWTHREAD.  */ +extern int pthread_create (pthread_t *__restrict __newthread, +			   __const pthread_attr_t *__restrict __attr, +			   void *(*__start_routine) (void *), +			   void *__restrict __arg) __THROW; + +/* Terminate calling thread. + +   The registered cleanup handlers are called via exception handling +   so we cannot mark this function with __THROW.*/ +extern void pthread_exit (void *__retval) __attribute__ ((__noreturn__)); + +/* Make calling thread wait for termination of the thread TH.  The +   exit status of the thread is stored in *THREAD_RETURN, if THREAD_RETURN +   is not NULL. + +   This function is a cancellation point and therefore not marked with +   __THROW.  */ +extern int pthread_join (pthread_t __th, void **__thread_return); + +#ifdef __USE_GNU +/* Check whether thread TH has terminated.  If yes return the status of +   the thread in *THREAD_RETURN, if THREAD_RETURN is not NULL.  */ +extern int pthread_tryjoin_np (pthread_t __th, void **__thread_return) __THROW; + +/* Make calling thread wait for termination of the thread TH, but only +   until TIMEOUT.  The exit status of the thread is stored in +   *THREAD_RETURN, if THREAD_RETURN is not NULL. + +   This function is a cancellation point and therefore not marked with +   __THROW.  */ +extern int pthread_timedjoin_np (pthread_t __th, void **__thread_return, +				 __const struct timespec *__abstime); +#endif + +/* Indicate that the thread TH is never to be joined with PTHREAD_JOIN. +   The resources of TH will therefore be freed immediately when it +   terminates, instead of waiting for another thread to perform PTHREAD_JOIN +   on it.  */ +extern int pthread_detach (pthread_t __th) __THROW; + + +/* Obtain the identifier of the current thread.  */ +extern pthread_t pthread_self (void) __THROW __attribute__ ((__const__)); + +/* Compare two thread identifiers.  */ +extern int pthread_equal (pthread_t __thread1, pthread_t __thread2) __THROW; + + +/* Thread attribute handling.  */ + +/* Initialize thread attribute *ATTR with default attributes +   (detachstate is PTHREAD_JOINABLE, scheduling policy is SCHED_OTHER, +    no user-provided stack).  */ +extern int pthread_attr_init (pthread_attr_t *__attr) __THROW; + +/* Destroy thread attribute *ATTR.  */ +extern int pthread_attr_destroy (pthread_attr_t *__attr) __THROW; + +/* Get detach state attribute.  */ +extern int pthread_attr_getdetachstate (__const pthread_attr_t *__attr, +					int *__detachstate) __THROW; + +/* Set detach state attribute.  */ +extern int pthread_attr_setdetachstate (pthread_attr_t *__attr, +					int __detachstate) __THROW; + + +/* Get the size of the guard area created for stack overflow protection.  */ +extern int pthread_attr_getguardsize (__const pthread_attr_t *__attr, +				      size_t *__guardsize) __THROW; + +/* Set the size of the guard area created for stack overflow protection.  */ +extern int pthread_attr_setguardsize (pthread_attr_t *__attr, +				      size_t __guardsize) __THROW; + + +/* Return in *PARAM the scheduling parameters of *ATTR.  */ +extern int pthread_attr_getschedparam (__const pthread_attr_t *__restrict +				       __attr, +				       struct sched_param *__restrict __param) +     __THROW; + +/* Set scheduling parameters (priority, etc) in *ATTR according to PARAM.  */ +extern int pthread_attr_setschedparam (pthread_attr_t *__restrict __attr, +				       __const struct sched_param *__restrict +				       __param) __THROW; + +/* Return in *POLICY the scheduling policy of *ATTR.  */ +extern int pthread_attr_getschedpolicy (__const pthread_attr_t *__restrict +					__attr, int *__restrict __policy) +     __THROW; + +/* Set scheduling policy in *ATTR according to POLICY.  */ +extern int pthread_attr_setschedpolicy (pthread_attr_t *__attr, int __policy) +     __THROW; + +/* Return in *INHERIT the scheduling inheritance mode of *ATTR.  */ +extern int pthread_attr_getinheritsched (__const pthread_attr_t *__restrict +					 __attr, int *__restrict __inherit) +     __THROW; + +/* Set scheduling inheritance mode in *ATTR according to INHERIT.  */ +extern int pthread_attr_setinheritsched (pthread_attr_t *__attr, +					 int __inherit) __THROW; + + +/* Return in *SCOPE the scheduling contention scope of *ATTR.  */ +extern int pthread_attr_getscope (__const pthread_attr_t *__restrict __attr, +				  int *__restrict __scope) __THROW; + +/* Set scheduling contention scope in *ATTR according to SCOPE.  */ +extern int pthread_attr_setscope (pthread_attr_t *__attr, int __scope) +     __THROW; + +/* Return the previously set address for the stack.  */ +extern int pthread_attr_getstackaddr (__const pthread_attr_t *__restrict +				      __attr, void **__restrict __stackaddr) +     __THROW __attribute_deprecated__; + +/* Set the starting address of the stack of the thread to be created. +   Depending on whether the stack grows up or down the value must either +   be higher or lower than all the address in the memory block.  The +   minimal size of the block must be PTHREAD_STACK_MIN.  */ +extern int pthread_attr_setstackaddr (pthread_attr_t *__attr, +				      void *__stackaddr) +     __THROW __attribute_deprecated__; + +/* Return the currently used minimal stack size.  */ +extern int pthread_attr_getstacksize (__const pthread_attr_t *__restrict +				      __attr, size_t *__restrict __stacksize) +     __THROW; + +/* Add information about the minimum stack size needed for the thread +   to be started.  This size must never be less than PTHREAD_STACK_MIN +   and must also not exceed the system limits.  */ +extern int pthread_attr_setstacksize (pthread_attr_t *__attr, +				      size_t __stacksize) __THROW; + +#ifdef __USE_XOPEN2K +/* Return the previously set address for the stack.  */ +extern int pthread_attr_getstack (__const pthread_attr_t *__restrict __attr, +				  void **__restrict __stackaddr, +				  size_t *__restrict __stacksize) __THROW; + +/* The following two interfaces are intended to replace the last two.  They +   require setting the address as well as the size since only setting the +   address will make the implementation on some architectures impossible.  */ +extern int pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr, +				  size_t __stacksize) __THROW; +#endif + +#ifdef __USE_GNU +/* Thread created with attribute ATTR will be limited to run only on +   the processors represented in CPUSET.  */ +extern int pthread_attr_setaffinity_np (pthread_attr_t *__attr, +					size_t __cpusetsize, +					__const cpu_set_t *__cpuset) __THROW; + +/* Get bit set in CPUSET representing the processors threads created with +   ATTR can run on.  */ +extern int pthread_attr_getaffinity_np (__const pthread_attr_t *__attr, +					size_t __cpusetsize, +					cpu_set_t *__cpuset) __THROW; + + +/* Initialize thread attribute *ATTR with attributes corresponding to the +   already running thread TH.  It shall be called on unitialized ATTR +   and destroyed with pthread_attr_destroy when no longer needed.  */ +extern int pthread_getattr_np (pthread_t __th, pthread_attr_t *__attr) __THROW; +#endif + + +/* Functions for scheduling control.  */ + +/* Set the scheduling parameters for TARGET_THREAD according to POLICY +   and *PARAM.  */ +extern int pthread_setschedparam (pthread_t __target_thread, int __policy, +				  __const struct sched_param *__param) +     __THROW; + +/* Return in *POLICY and *PARAM the scheduling parameters for TARGET_THREAD. */ +extern int pthread_getschedparam (pthread_t __target_thread, +				  int *__restrict __policy, +				  struct sched_param *__restrict __param) +     __THROW; + +/* Set the scheduling priority for TARGET_THREAD.  */ +extern int pthread_setschedprio (pthread_t __target_thread, int __prio) +     __THROW; + + +#ifdef __USE_UNIX98 +/* Determine level of concurrency.  */ +extern int pthread_getconcurrency (void) __THROW; + +/* Set new concurrency level to LEVEL.  */ +extern int pthread_setconcurrency (int __level) __THROW; +#endif + +#ifdef __USE_GNU +/* Yield the processor to another thread or process. +   This function is similar to the POSIX `sched_yield' function but +   might be differently implemented in the case of a m-on-n thread +   implementation.  */ +extern int pthread_yield (void) __THROW; + + +/* Limit specified thread TH to run only on the processors represented +   in CPUSET.  */ +extern int pthread_setaffinity_np (pthread_t __th, size_t __cpusetsize, +				   __const cpu_set_t *__cpuset) __THROW; + +/* Get bit set in CPUSET representing the processors TH can run on.  */ +extern int pthread_getaffinity_np (pthread_t __th, size_t __cpusetsize, +				   cpu_set_t *__cpuset) __THROW; +#endif + + +/* Functions for handling initialization.  */ + +/* Guarantee that the initialization function INIT_ROUTINE will be called +   only once, even if pthread_once is executed several times with the +   same ONCE_CONTROL argument. ONCE_CONTROL must point to a static or +   extern variable initialized to PTHREAD_ONCE_INIT. + +   The initialization functions might throw exception which is why +   this function is not marked with __THROW.  */ +extern int pthread_once (pthread_once_t *__once_control, +			 void (*__init_routine) (void)); + + +/* Functions for handling cancellation. + +   Note that these functions are explicitly not marked to not throw an +   exception in C++ code.  If cancellation is implemented by unwinding +   this is necessary to have the compiler generate the unwind information.  */ + +/* Set cancelability state of current thread to STATE, returning old +   state in *OLDSTATE if OLDSTATE is not NULL.  */ +extern int pthread_setcancelstate (int __state, int *__oldstate); + +/* Set cancellation state of current thread to TYPE, returning the old +   type in *OLDTYPE if OLDTYPE is not NULL.  */ +extern int pthread_setcanceltype (int __type, int *__oldtype); + +/* Cancel THREAD immediately or at the next possibility.  */ +extern int pthread_cancel (pthread_t __th); + +/* Test for pending cancellation for the current thread and terminate +   the thread as per pthread_exit(PTHREAD_CANCELED) if it has been +   cancelled.  */ +extern void pthread_testcancel (void); + + +/* Cancellation handling with integration into exception handling.  */ + +typedef struct +{ +  struct +  { +    __jmp_buf __cancel_jmp_buf; +    int __mask_was_saved; +  } __cancel_jmp_buf[1]; +  void *__pad[4]; +} __pthread_unwind_buf_t __attribute__ ((__aligned__)); + +/* No special attributes by default.  */ +#ifndef __cleanup_fct_attribute +# define __cleanup_fct_attribute +#endif + + +/* Structure to hold the cleanup handler information.  */ +struct __pthread_cleanup_frame +{ +  void (*__cancel_routine) (void *); +  void *__cancel_arg; +  int __do_it; +  int __cancel_type; +}; + +#if defined __GNUC__ && defined __EXCEPTIONS +# ifdef __cplusplus +/* Class to handle cancellation handler invocation.  */ +class __pthread_cleanup_class +{ +  void (*__cancel_routine) (void *); +  void *__cancel_arg; +  int __do_it; +  int __cancel_type; + + public: +  __pthread_cleanup_class (void (*__fct) (void *), void *__arg) +    : __cancel_routine (__fct), __cancel_arg (__arg), __do_it (1) { } +  ~__pthread_cleanup_class () { if (__do_it) __cancel_routine (__cancel_arg); } +  void __setdoit (int __newval) { __do_it = __newval; } +  void __defer () { pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, +					   &__cancel_type); } +  void __restore () const { pthread_setcanceltype (__cancel_type, 0); } +}; + +/* Install a cleanup handler: ROUTINE will be called with arguments ARG +   when the thread is canceled or calls pthread_exit.  ROUTINE will also +   be called with arguments ARG when the matching pthread_cleanup_pop +   is executed with non-zero EXECUTE argument. + +   pthread_cleanup_push and pthread_cleanup_pop are macros and must always +   be used in matching pairs at the same nesting level of braces.  */ +#  define pthread_cleanup_push(routine, arg) \ +  do {									      \ +    __pthread_cleanup_class __clframe (routine, arg) + +/* Remove a cleanup handler installed by the matching pthread_cleanup_push. +   If EXECUTE is non-zero, the handler function is called. */ +#  define pthread_cleanup_pop(execute) \ +    __clframe.__setdoit (execute);					      \ +  } while (0) + +#  ifdef __USE_GNU +/* Install a cleanup handler as pthread_cleanup_push does, but also +   saves the current cancellation type and sets it to deferred +   cancellation.  */ +#   define pthread_cleanup_push_defer_np(routine, arg) \ +  do {									      \ +    __pthread_cleanup_class __clframe (routine, arg);			      \ +    __clframe.__defer () + +/* Remove a cleanup handler as pthread_cleanup_pop does, but also +   restores the cancellation type that was in effect when the matching +   pthread_cleanup_push_defer was called.  */ +#   define pthread_cleanup_pop_restore_np(execute) \ +    __clframe.__restore ();						      \ +    __clframe.__setdoit (execute);					      \ +  } while (0) +#  endif +# else +/* Function called to call the cleanup handler.  As an extern inline +   function the compiler is free to decide inlining the change when +   needed or fall back on the copy which must exist somewhere +   else.  */ +__extern_inline void +__pthread_cleanup_routine (struct __pthread_cleanup_frame *__frame); + +__extern_inline void +__pthread_cleanup_routine (struct __pthread_cleanup_frame *__frame) +{ +  if (__frame->__do_it) +    __frame->__cancel_routine (__frame->__cancel_arg); +} + +/* Install a cleanup handler: ROUTINE will be called with arguments ARG +   when the thread is canceled or calls pthread_exit.  ROUTINE will also +   be called with arguments ARG when the matching pthread_cleanup_pop +   is executed with non-zero EXECUTE argument. + +   pthread_cleanup_push and pthread_cleanup_pop are macros and must always +   be used in matching pairs at the same nesting level of braces.  */ +#  define pthread_cleanup_push(routine, arg) \ +  do {									      \ +    struct __pthread_cleanup_frame __clframe				      \ +      __attribute__ ((__cleanup__ (__pthread_cleanup_routine)))		      \ +      = { .__cancel_routine = (routine), .__cancel_arg = (arg),	 	      \ +	  .__do_it = 1 }; + +/* Remove a cleanup handler installed by the matching pthread_cleanup_push. +   If EXECUTE is non-zero, the handler function is called. */ +#  define pthread_cleanup_pop(execute) \ +    __clframe.__do_it = (execute);					      \ +  } while (0) + +#  ifdef __USE_GNU +/* Install a cleanup handler as pthread_cleanup_push does, but also +   saves the current cancellation type and sets it to deferred +   cancellation.  */ +#   define pthread_cleanup_push_defer_np(routine, arg) \ +  do {									      \ +    struct __pthread_cleanup_frame __clframe				      \ +      __attribute__ ((__cleanup__ (__pthread_cleanup_routine)))		      \ +      = { .__cancel_routine = (routine), .__cancel_arg = (arg),		      \ +	  .__do_it = 1 };						      \ +    (void) pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED,		      \ +				  &__clframe.__cancel_type) + +/* Remove a cleanup handler as pthread_cleanup_pop does, but also +   restores the cancellation type that was in effect when the matching +   pthread_cleanup_push_defer was called.  */ +#   define pthread_cleanup_pop_restore_np(execute) \ +    (void) pthread_setcanceltype (__clframe.__cancel_type, NULL);	      \ +    __clframe.__do_it = (execute);					      \ +  } while (0) +#  endif +# endif +#else +/* Install a cleanup handler: ROUTINE will be called with arguments ARG +   when the thread is canceled or calls pthread_exit.  ROUTINE will also +   be called with arguments ARG when the matching pthread_cleanup_pop +   is executed with non-zero EXECUTE argument. + +   pthread_cleanup_push and pthread_cleanup_pop are macros and must always +   be used in matching pairs at the same nesting level of braces.  */ +# define pthread_cleanup_push(routine, arg) \ +  do {									      \ +    __pthread_unwind_buf_t __cancel_buf;				      \ +    void (*__cancel_routine) (void *) = (routine);			      \ +    void *__cancel_arg = (arg);						      \ +    int not_first_call = __sigsetjmp ((struct __jmp_buf_tag *)		      \ +				      __cancel_buf.__cancel_jmp_buf, 0);      \ +    if (__builtin_expect (not_first_call, 0))				      \ +      {									      \ +	__cancel_routine (__cancel_arg);				      \ +	__pthread_unwind_next (&__cancel_buf);				      \ +	/* NOTREACHED */						      \ +      }									      \ +									      \ +    __pthread_register_cancel (&__cancel_buf);				      \ +    do { +extern void __pthread_register_cancel (__pthread_unwind_buf_t *__buf) +     __cleanup_fct_attribute; + +/* Remove a cleanup handler installed by the matching pthread_cleanup_push. +   If EXECUTE is non-zero, the handler function is called. */ +# define pthread_cleanup_pop(execute) \ +    } while (0);							      \ +    __pthread_unregister_cancel (&__cancel_buf);			      \ +    if (execute)							      \ +      __cancel_routine (__cancel_arg);					      \ +  } while (0) +extern void __pthread_unregister_cancel (__pthread_unwind_buf_t *__buf) +  __cleanup_fct_attribute; + +# ifdef __USE_GNU +/* Install a cleanup handler as pthread_cleanup_push does, but also +   saves the current cancellation type and sets it to deferred +   cancellation.  */ +#  define pthread_cleanup_push_defer_np(routine, arg) \ +  do {									      \ +    __pthread_unwind_buf_t __cancel_buf;				      \ +    void (*__cancel_routine) (void *) = (routine);			      \ +    void *__cancel_arg = (arg);						      \ +    int not_first_call = __sigsetjmp ((struct __jmp_buf_tag *)		      \ +				      __cancel_buf.__cancel_jmp_buf, 0);      \ +    if (__builtin_expect (not_first_call, 0))				      \ +      {									      \ +	__cancel_routine (__cancel_arg);				      \ +	__pthread_unwind_next (&__cancel_buf);				      \ +	/* NOTREACHED */						      \ +      }									      \ +									      \ +    __pthread_register_cancel_defer (&__cancel_buf);			      \ +    do { +extern void __pthread_register_cancel_defer (__pthread_unwind_buf_t *__buf) +     __cleanup_fct_attribute; + +/* Remove a cleanup handler as pthread_cleanup_pop does, but also +   restores the cancellation type that was in effect when the matching +   pthread_cleanup_push_defer was called.  */ +#  define pthread_cleanup_pop_restore_np(execute) \ +    } while (0);							      \ +    __pthread_unregister_cancel_restore (&__cancel_buf);		      \ +    if (execute)							      \ +      __cancel_routine (__cancel_arg);					      \ +  } while (0) +extern void __pthread_unregister_cancel_restore (__pthread_unwind_buf_t *__buf) +  __cleanup_fct_attribute; +# endif + +/* Internal interface to initiate cleanup.  */ +extern void __pthread_unwind_next (__pthread_unwind_buf_t *__buf) +     __cleanup_fct_attribute __attribute ((__noreturn__)) +# ifndef SHARED +     __attribute ((__weak__)) +# endif +     ; +#endif + +/* Function used in the macros.  */ +struct __jmp_buf_tag; +extern int __sigsetjmp (struct __jmp_buf_tag *__env, int __savemask) __THROW; + + +/* Mutex handling.  */ + +/* Initialize a mutex.  */ +extern int pthread_mutex_init (pthread_mutex_t *__mutex, +			       __const pthread_mutexattr_t *__mutexattr) +     __THROW; + +/* Destroy a mutex.  */ +extern int pthread_mutex_destroy (pthread_mutex_t *__mutex) __THROW; + +/* Try locking a mutex.  */ +extern int pthread_mutex_trylock (pthread_mutex_t *_mutex) __THROW; + +/* Lock a mutex.  */ +extern int pthread_mutex_lock (pthread_mutex_t *__mutex) __THROW; + +#ifdef __USE_XOPEN2K +/* Wait until lock becomes available, or specified time passes. */ +extern int pthread_mutex_timedlock (pthread_mutex_t *__restrict __mutex, +                                    __const struct timespec *__restrict +                                    __abstime) __THROW; +#endif + +/* Unlock a mutex.  */ +extern int pthread_mutex_unlock (pthread_mutex_t *__mutex) __THROW; + + +/* Functions for handling mutex attributes.  */ + +/* Initialize mutex attribute object ATTR with default attributes +   (kind is PTHREAD_MUTEX_TIMED_NP).  */ +extern int pthread_mutexattr_init (pthread_mutexattr_t *__attr) __THROW; + +/* Destroy mutex attribute object ATTR.  */ +extern int pthread_mutexattr_destroy (pthread_mutexattr_t *__attr) __THROW; + +/* Get the process-shared flag of the mutex attribute ATTR.  */ +extern int pthread_mutexattr_getpshared (__const pthread_mutexattr_t * +					 __restrict __attr, +					 int *__restrict __pshared) __THROW; + +/* Set the process-shared flag of the mutex attribute ATTR.  */ +extern int pthread_mutexattr_setpshared (pthread_mutexattr_t *__attr, +					 int __pshared) __THROW; + +#ifdef __USE_UNIX98 +/* Return in *KIND the mutex kind attribute in *ATTR.  */ +extern int pthread_mutexattr_gettype (__const pthread_mutexattr_t *__restrict +				      __attr, int *__restrict __kind) __THROW; + +/* Set the mutex kind attribute in *ATTR to KIND (either PTHREAD_MUTEX_NORMAL, +   PTHREAD_MUTEX_RECURSIVE, PTHREAD_MUTEX_ERRORCHECK, or +   PTHREAD_MUTEX_DEFAULT).  */ +extern int pthread_mutexattr_settype (pthread_mutexattr_t *__attr, int __kind) +     __THROW; +#endif + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Functions for handling read-write locks.  */ + +/* Initialize read-write lock RWLOCK using attributes ATTR, or use +   the default values if later is NULL.  */ +extern int pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock, +				__const pthread_rwlockattr_t *__restrict +				__attr) __THROW; + +/* Destroy read-write lock RWLOCK.  */ +extern int pthread_rwlock_destroy (pthread_rwlock_t *__rwlock) __THROW; + +/* Acquire read lock for RWLOCK.  */ +extern int pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock) __THROW; + +/* Try to acquire read lock for RWLOCK.  */ +extern int pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock) __THROW; + +# ifdef __USE_XOPEN2K +/* Try to acquire read lock for RWLOCK or return after specfied time.  */ +extern int pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock, +				       __const struct timespec *__restrict +				       __abstime) __THROW; +# endif + +/* Acquire write lock for RWLOCK.  */ +extern int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock) __THROW; + +/* Try to acquire write lock for RWLOCK.  */ +extern int pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock) __THROW; + +# ifdef __USE_XOPEN2K +/* Try to acquire write lock for RWLOCK or return after specfied time.  */ +extern int pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock, +				       __const struct timespec *__restrict +				       __abstime) __THROW; +# endif + +/* Unlock RWLOCK.  */ +extern int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock) __THROW; + + +/* Functions for handling read-write lock attributes.  */ + +/* Initialize attribute object ATTR with default values.  */ +extern int pthread_rwlockattr_init (pthread_rwlockattr_t *__attr) __THROW; + +/* Destroy attribute object ATTR.  */ +extern int pthread_rwlockattr_destroy (pthread_rwlockattr_t *__attr) __THROW; + +/* Return current setting of process-shared attribute of ATTR in PSHARED.  */ +extern int pthread_rwlockattr_getpshared (__const pthread_rwlockattr_t * +					  __restrict __attr, +					  int *__restrict __pshared) __THROW; + +/* Set process-shared attribute of ATTR to PSHARED.  */ +extern int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *__attr, +					  int __pshared) __THROW; + +/* Return current setting of reader/writer preference.  */ +extern int pthread_rwlockattr_getkind_np (__const pthread_rwlockattr_t * +					  __restrict __attr, +					  int *__restrict __pref) __THROW; + +/* Set reader/write preference.  */ +extern int pthread_rwlockattr_setkind_np (pthread_rwlockattr_t *__attr, +					  int __pref) __THROW; +#endif + + +/* Functions for handling conditional variables.  */ + +/* Initialize condition variable COND using attributes ATTR, or use +   the default values if later is NULL.  */ +extern int pthread_cond_init (pthread_cond_t *__restrict __cond, +			      __const pthread_condattr_t *__restrict +			      __cond_attr) __THROW; + +/* Destroy condition variable COND.  */ +extern int pthread_cond_destroy (pthread_cond_t *__cond) __THROW; + +/* Wake up one thread waiting for condition variable COND.  */ +extern int pthread_cond_signal (pthread_cond_t *__cond) __THROW; + +/* Wake up all threads waiting for condition variables COND.  */ +extern int pthread_cond_broadcast (pthread_cond_t *__cond) __THROW; + +/* Wait for condition variable COND to be signaled or broadcast. +   MUTEX is assumed to be locked before. + +   This function is a cancellation point and therefore not marked with +   __THROW.  */ +extern int pthread_cond_wait (pthread_cond_t *__restrict __cond, +			      pthread_mutex_t *__restrict __mutex); + +/* Wait for condition variable COND to be signaled or broadcast until +   ABSTIME.  MUTEX is assumed to be locked before.  ABSTIME is an +   absolute time specification; zero is the beginning of the epoch +   (00:00:00 GMT, January 1, 1970). + +   This function is a cancellation point and therefore not marked with +   __THROW.  */ +extern int pthread_cond_timedwait (pthread_cond_t *__restrict __cond, +				   pthread_mutex_t *__restrict __mutex, +				   __const struct timespec *__restrict +				   __abstime); + +/* Functions for handling condition variable attributes.  */ + +/* Initialize condition variable attribute ATTR.  */ +extern int pthread_condattr_init (pthread_condattr_t *__attr) __THROW; + +/* Destroy condition variable attribute ATTR.  */ +extern int pthread_condattr_destroy (pthread_condattr_t *__attr) __THROW; + +/* Get the process-shared flag of the condition variable attribute ATTR.  */ +extern int pthread_condattr_getpshared (__const pthread_condattr_t * +                                        __restrict __attr, +                                        int *__restrict __pshared) __THROW; + +/* Set the process-shared flag of the condition variable attribute ATTR.  */ +extern int pthread_condattr_setpshared (pthread_condattr_t *__attr, +                                        int __pshared) __THROW; + +#ifdef __USE_XOPEN2K +/* Get the clock selected for the conditon variable attribute ATTR.  */ +extern int pthread_condattr_getclock (__const pthread_condattr_t * +				      __restrict __attr, +				      __clockid_t *__restrict __clock_id) +     __THROW; + +/* Set the clock selected for the conditon variable attribute ATTR.  */ +extern int pthread_condattr_setclock (pthread_condattr_t *__attr, +				      __clockid_t __clock_id) __THROW; + +#endif + + +#ifdef __USE_XOPEN2K +/* Functions to handle spinlocks.  */ + +/* Initialize the spinlock LOCK.  If PSHARED is nonzero the spinlock can +   be shared between different processes.  */ +extern int pthread_spin_init (pthread_spinlock_t *__lock, int __pshared) +     __THROW; + +/* Destroy the spinlock LOCK.  */ +extern int pthread_spin_destroy (pthread_spinlock_t *__lock) __THROW; + +/* Wait until spinlock LOCK is retrieved.  */ +extern int pthread_spin_lock (pthread_spinlock_t *__lock) __THROW; + +/* Try to lock spinlock LOCK.  */ +extern int pthread_spin_trylock (pthread_spinlock_t *__lock) __THROW; + +/* Release spinlock LOCK.  */ +extern int pthread_spin_unlock (pthread_spinlock_t *__lock) __THROW; + + +/* Functions to handle barriers.  */ + +/* Initialize BARRIER with the attributes in ATTR.  The barrier is +   opened when COUNT waiters arrived.  */ +extern int pthread_barrier_init (pthread_barrier_t *__restrict __barrier, +				 __const pthread_barrierattr_t *__restrict +				 __attr, unsigned int __count) __THROW; + +/* Destroy a previously dynamically initialized barrier BARRIER.  */ +extern int pthread_barrier_destroy (pthread_barrier_t *__barrier) __THROW; + +/* Wait on barrier BARRIER.  */ +extern int pthread_barrier_wait (pthread_barrier_t *__barrier) __THROW; + + +/* Initialize barrier attribute ATTR.  */ +extern int pthread_barrierattr_init (pthread_barrierattr_t *__attr) __THROW; + +/* Destroy previously dynamically initialized barrier attribute ATTR.  */ +extern int pthread_barrierattr_destroy (pthread_barrierattr_t *__attr) __THROW; + +/* Get the process-shared flag of the barrier attribute ATTR.  */ +extern int pthread_barrierattr_getpshared (__const pthread_barrierattr_t * +					   __restrict __attr, +					   int *__restrict __pshared) __THROW; + +/* Set the process-shared flag of the barrier attribute ATTR.  */ +extern int pthread_barrierattr_setpshared (pthread_barrierattr_t *__attr, +                                           int __pshared) __THROW; +#endif + + +/* Functions for handling thread-specific data.  */ + +/* Create a key value identifying a location in the thread-specific +   data area.  Each thread maintains a distinct thread-specific data +   area.  DESTR_FUNCTION, if non-NULL, is called with the value +   associated to that key when the key is destroyed. +   DESTR_FUNCTION is not called if the value associated is NULL when +   the key is destroyed.  */ +extern int pthread_key_create (pthread_key_t *__key, +			       void (*__destr_function) (void *)) __THROW; + +/* Destroy KEY.  */ +extern int pthread_key_delete (pthread_key_t __key) __THROW; + +/* Return current value of the thread-specific data slot identified by KEY.  */ +extern void *pthread_getspecific (pthread_key_t __key) __THROW; + +/* Store POINTER in the thread-specific data slot identified by KEY. */ +extern int pthread_setspecific (pthread_key_t __key, +				__const void *__pointer) __THROW; + + +#ifdef __USE_XOPEN2K +/* Get ID of CPU-time clock for thread THREAD_ID.  */ +extern int pthread_getcpuclockid (pthread_t __thread_id, +				  __clockid_t *__clock_id) __THROW; +#endif + + +/* Install handlers to be called when a new process is created with FORK. +   The PREPARE handler is called in the parent process just before performing +   FORK. The PARENT handler is called in the parent process just after FORK. +   The CHILD handler is called in the child process.  Each of the three +   handlers can be NULL, meaning that no handler needs to be called at that +   point. +   PTHREAD_ATFORK can be called several times, in which case the PREPARE +   handlers are called in LIFO order (last added with PTHREAD_ATFORK, +   first called before FORK), and the PARENT and CHILD handlers are called +   in FIFO (first added, first called).  */ + +extern int pthread_atfork (void (*__prepare) (void), +			   void (*__parent) (void), +			   void (*__child) (void)) __THROW; + +__END_DECLS + +#endif	/* pthread.h */ diff --git a/libpthread/nptl/sysdeps/pthread/pthread_barrier_wait.c b/libpthread/nptl/sysdeps/pthread/pthread_barrier_wait.c new file mode 100644 index 000000000..d21ed79b1 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_barrier_wait.c @@ -0,0 +1,76 @@ +/* Copyright (C) 2003, 2004 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) +{ +  struct pthread_barrier *ibarrier = (struct pthread_barrier *) barrier; +  int result = 0; + +  /* Make sure we are alone.  */ +  lll_lock (ibarrier->lock); + +  /* One more arrival.  */ +  --ibarrier->left; + +  /* Are these all?  */ +  if (ibarrier->left == 0) +    { +      /* Yes. Increment the event counter to avoid invalid wake-ups and +	 tell the current waiters that it is their turn.  */ +      ++ibarrier->curr_event; + +      /* Wake up everybody.  */ +      lll_futex_wake (&ibarrier->curr_event, INT_MAX); + +      /* 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->curr_event; + +      /* Before suspending, make the barrier available to others.  */ +      lll_unlock (ibarrier->lock); + +      /* Wait for the event counter of the barrier to change.  */ +      do +	lll_futex_wait (&ibarrier->curr_event, event); +      while (event == ibarrier->curr_event); +    } + +  /* Make sure the init_count is stored locally or in a register.  */ +  unsigned int init_count = ibarrier->init_count; + +  /* If this was the last woken thread, unlock.  */ +  if (atomic_increment_val (&ibarrier->left) == init_count) +    /* We are done.  */ +    lll_unlock (ibarrier->lock); + +  return result; +} diff --git a/libpthread/nptl/sysdeps/pthread/pthread_cond_broadcast.c b/libpthread/nptl/sysdeps/pthread/pthread_cond_broadcast.c new file mode 100644 index 000000000..f6e83ed3f --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_cond_broadcast.c @@ -0,0 +1,75 @@ +/* Copyright (C) 2003, 2004 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 <endian.h> +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> +#include <bits/kernel-features.h> + + +int +__pthread_cond_broadcast (pthread_cond_t *cond) +{ +  /* Make sure we are alone.  */ +  lll_mutex_lock (cond->__data.__lock); + +  /* Are there any waiters to be woken?  */ +  if (cond->__data.__total_seq > cond->__data.__wakeup_seq) +    { +      /* Yes.  Mark them all as woken.  */ +      cond->__data.__wakeup_seq = cond->__data.__total_seq; +      cond->__data.__woken_seq = cond->__data.__total_seq; +      cond->__data.__futex = (unsigned int) cond->__data.__total_seq * 2; +      int futex_val = cond->__data.__futex; +      /* Signal that a broadcast happened.  */ +      ++cond->__data.__broadcast_seq; + +      /* We are done.  */ +      lll_mutex_unlock (cond->__data.__lock); + +      /* Do not use requeue for pshared condvars.  */ +      if (cond->__data.__mutex == (void *) ~0l) +	goto wake_all; + +      /* Wake everybody.  */ +      pthread_mutex_t *mut = (pthread_mutex_t *) cond->__data.__mutex; +      /* lll_futex_requeue returns 0 for success and non-zero +	 for errors.  */ +      if (__builtin_expect (lll_futex_requeue (&cond->__data.__futex, 1, +					       INT_MAX, &mut->__data.__lock, +					       futex_val), 0)) +	{ +	  /* The requeue functionality is not available.  */ +	wake_all: +	  lll_futex_wake (&cond->__data.__futex, INT_MAX); +	} + +      /* That's all.  */ +      return 0; +    } + +  /* We are done.  */ +  lll_mutex_unlock (cond->__data.__lock); + +  return 0; +} +weak_alias(__pthread_cond_broadcast, pthread_cond_broadcast) diff --git a/libpthread/nptl/sysdeps/pthread/pthread_cond_signal.c b/libpthread/nptl/sysdeps/pthread/pthread_cond_signal.c new file mode 100644 index 000000000..5091bea87 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_cond_signal.c @@ -0,0 +1,51 @@ +/* Copyright (C) 2003, 2004 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 <endian.h> +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> +#include <bits/kernel-features.h> + + +int +__pthread_cond_signal (pthread_cond_t *cond) +{ +  /* Make sure we are alone.  */ +  lll_mutex_lock (cond->__data.__lock); + +  /* Are there any waiters to be woken?  */ +  if (cond->__data.__total_seq > cond->__data.__wakeup_seq) +    { +      /* Yes.  Mark one of them as woken.  */ +      ++cond->__data.__wakeup_seq; +      ++cond->__data.__futex; + +      /* Wake one.  */ +      lll_futex_wake (&cond->__data.__futex, 1); +    } + +  /* We are done.  */ +  lll_mutex_unlock (cond->__data.__lock); + +  return 0; +} +weak_alias(__pthread_cond_signal, pthread_cond_signal) diff --git a/libpthread/nptl/sysdeps/pthread/pthread_cond_timedwait.c b/libpthread/nptl/sysdeps/pthread/pthread_cond_timedwait.c new file mode 100644 index 000000000..1f4136e70 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_cond_timedwait.c @@ -0,0 +1,210 @@ +/* Copyright (C) 2003, 2004 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 <endian.h> +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> + + +/* Cleanup handler, defined in pthread_cond_wait.c.  */ +extern void __condvar_cleanup (void *arg) +     __attribute__ ((visibility ("hidden"))); + +struct _condvar_cleanup_buffer +{ +  int oldtype; +  pthread_cond_t *cond; +  pthread_mutex_t *mutex; +  unsigned int bc_seq; +}; + +int +__pthread_cond_timedwait ( +     pthread_cond_t *cond, +     pthread_mutex_t *mutex, +     const struct timespec *abstime) +{ +  struct _pthread_cleanup_buffer buffer; +  struct _condvar_cleanup_buffer cbuffer; +  int result = 0; + +  /* Catch invalid parameters.  */ +  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) +    return EINVAL; + +  /* Make sure we are along.  */ +  lll_mutex_lock (cond->__data.__lock); + +  /* Now we can release the mutex.  */ +  int err = __pthread_mutex_unlock_usercnt (mutex, 0); +  if (err) +    { +      lll_mutex_unlock (cond->__data.__lock); +      return err; +    } + +  /* We have one new user of the condvar.  */ +  ++cond->__data.__total_seq; +  ++cond->__data.__futex; +  cond->__data.__nwaiters += 1 << COND_CLOCK_BITS; + +  /* Remember the mutex we are using here.  If there is already a +     different address store this is a bad user bug.  Do not store +     anything for pshared condvars.  */ +  if (cond->__data.__mutex != (void *) ~0l) +    cond->__data.__mutex = mutex; + +  /* Prepare structure passed to cancellation handler.  */ +  cbuffer.cond = cond; +  cbuffer.mutex = mutex; + +  /* Before we block we enable cancellation.  Therefore we have to +     install a cancellation handler.  */ +  __pthread_cleanup_push (&buffer, __condvar_cleanup, &cbuffer); + +  /* The current values of the wakeup counter.  The "woken" counter +     must exceed this value.  */ +  unsigned long long int val; +  unsigned long long int seq; +  val = seq = cond->__data.__wakeup_seq; +  /* Remember the broadcast counter.  */ +  cbuffer.bc_seq = cond->__data.__broadcast_seq; + +  while (1) +    { +      struct timespec rt; +      { +#ifdef __NR_clock_gettime +	INTERNAL_SYSCALL_DECL (err); +	int ret; +	ret = INTERNAL_SYSCALL (clock_gettime, err, 2, +				(cond->__data.__nwaiters +				 & ((1 << COND_CLOCK_BITS) - 1)), +				&rt); +# ifndef __ASSUME_POSIX_TIMERS +	if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (ret, err), 0)) +	  { +	    struct timeval tv; +	    (void) gettimeofday (&tv, NULL); + +	    /* Convert the absolute timeout value to a relative timeout.  */ +	    rt.tv_sec = abstime->tv_sec - tv.tv_sec; +	    rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; +	  } +	else +# endif +	  { +	    /* Convert the absolute timeout value to a relative timeout.  */ +	    rt.tv_sec = abstime->tv_sec - rt.tv_sec; +	    rt.tv_nsec = abstime->tv_nsec - rt.tv_nsec; +	  } +#else +	/* Get the current time.  So far we support only one clock.  */ +	struct timeval tv; +	(void) gettimeofday (&tv, NULL); + +	/* Convert the absolute timeout value to a relative timeout.  */ +	rt.tv_sec = abstime->tv_sec - tv.tv_sec; +	rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; +#endif +      } +      if (rt.tv_nsec < 0) +	{ +	  rt.tv_nsec += 1000000000; +	  --rt.tv_sec; +	} +      /* Did we already time out?  */ +      if (__builtin_expect (rt.tv_sec < 0, 0)) +	{ +	  if (cbuffer.bc_seq != cond->__data.__broadcast_seq) +	    goto bc_out; + +	  goto timeout; +	} + +      unsigned int futex_val = cond->__data.__futex; + +      /* Prepare to wait.  Release the condvar futex.  */ +      lll_mutex_unlock (cond->__data.__lock); + +      /* Enable asynchronous cancellation.  Required by the standard.  */ +      cbuffer.oldtype = __pthread_enable_asynccancel (); + +      /* Wait until woken by signal or broadcast.  */ +      err = lll_futex_timed_wait (&cond->__data.__futex, +				  futex_val, &rt); + +      /* Disable asynchronous cancellation.  */ +      __pthread_disable_asynccancel (cbuffer.oldtype); + +      /* We are going to look at shared data again, so get the lock.  */ +      lll_mutex_lock(cond->__data.__lock); + +      /* If a broadcast happened, we are done.  */ +      if (cbuffer.bc_seq != cond->__data.__broadcast_seq) +	goto bc_out; + +      /* Check whether we are eligible for wakeup.  */ +      val = cond->__data.__wakeup_seq; +      if (val != seq && cond->__data.__woken_seq != val) +	break; + +      /* Not woken yet.  Maybe the time expired?  */ +      if (__builtin_expect (err == -ETIMEDOUT, 0)) +	{ +	timeout: +	  /* Yep.  Adjust the counters.  */ +	  ++cond->__data.__wakeup_seq; +	  ++cond->__data.__futex; + +	  /* The error value.  */ +	  result = ETIMEDOUT; +	  break; +	} +    } + +  /* Another thread woken up.  */ +  ++cond->__data.__woken_seq; + + bc_out: + +  cond->__data.__nwaiters -= 1 << COND_CLOCK_BITS; + +  /* If pthread_cond_destroy was called on this variable already, +     notify the pthread_cond_destroy caller all waiters have left +     and it can be successfully destroyed.  */ +  if (cond->__data.__total_seq == -1ULL +      && cond->__data.__nwaiters < (1 << COND_CLOCK_BITS)) +    lll_futex_wake (&cond->__data.__nwaiters, 1); + +  /* We are done with the condvar.  */ +  lll_mutex_unlock (cond->__data.__lock); + +  /* The cancellation handling is back to normal, remove the handler.  */ +  __pthread_cleanup_pop (&buffer, 0); + +  /* Get the mutex before returning.  */ +  err = __pthread_mutex_cond_lock (mutex); + +  return err ?: result; +} +weak_alias(__pthread_cond_timedwait, pthread_cond_timedwait) diff --git a/libpthread/nptl/sysdeps/pthread/pthread_cond_wait.c b/libpthread/nptl/sysdeps/pthread/pthread_cond_wait.c new file mode 100644 index 000000000..79245b7c1 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_cond_wait.c @@ -0,0 +1,181 @@ +/* Copyright (C) 2003, 2004 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 <endian.h> +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <pthread.h> +#include <pthreadP.h> + + +struct _condvar_cleanup_buffer +{ +  int oldtype; +  pthread_cond_t *cond; +  pthread_mutex_t *mutex; +  unsigned int bc_seq; +}; + + +void +__attribute__ ((visibility ("hidden"))) +__condvar_cleanup (void *arg) +{ +  struct _condvar_cleanup_buffer *cbuffer = +    (struct _condvar_cleanup_buffer *) arg; +  unsigned int destroying; + +  /* We are going to modify shared data.  */ +  lll_mutex_lock (cbuffer->cond->__data.__lock); + +  if (cbuffer->bc_seq == cbuffer->cond->__data.__broadcast_seq) +    { +      /* This thread is not waiting anymore.  Adjust the sequence counters +	 appropriately.  */ +      ++cbuffer->cond->__data.__wakeup_seq; +      ++cbuffer->cond->__data.__woken_seq; +      ++cbuffer->cond->__data.__futex; +    } + +  cbuffer->cond->__data.__nwaiters -= 1 << COND_CLOCK_BITS; + +  /* If pthread_cond_destroy was called on this variable already, +     notify the pthread_cond_destroy caller all waiters have left +     and it can be successfully destroyed.  */ +  destroying = 0; +  if (cbuffer->cond->__data.__total_seq == -1ULL +      && cbuffer->cond->__data.__nwaiters < (1 << COND_CLOCK_BITS)) +    { +      lll_futex_wake (&cbuffer->cond->__data.__nwaiters, 1); +      destroying = 1; +    } + +  /* We are done.  */ +  lll_mutex_unlock (cbuffer->cond->__data.__lock); + +  /* Wake everybody to make sure no condvar signal gets lost.  */ +  if (! destroying) +    lll_futex_wake (&cbuffer->cond->__data.__futex, INT_MAX); + +  /* Get the mutex before returning unless asynchronous cancellation +     is in effect.  */ +  __pthread_mutex_cond_lock (cbuffer->mutex); +} + + +int +__pthread_cond_wait ( +     pthread_cond_t *cond, +     pthread_mutex_t *mutex) +{ +  struct _pthread_cleanup_buffer buffer; +  struct _condvar_cleanup_buffer cbuffer; +  int err; + +  /* Make sure we are along.  */ +  lll_mutex_lock (cond->__data.__lock); + +  /* Now we can release the mutex.  */ +  err = __pthread_mutex_unlock_usercnt (mutex, 0); +  if (__builtin_expect (err, 0)) +    { +      lll_mutex_unlock (cond->__data.__lock); +      return err; +    } + +  /* We have one new user of the condvar.  */ +  ++cond->__data.__total_seq; +  ++cond->__data.__futex; +  cond->__data.__nwaiters += 1 << COND_CLOCK_BITS; + +  /* Remember the mutex we are using here.  If there is already a +     different address store this is a bad user bug.  Do not store +     anything for pshared condvars.  */ +  if (cond->__data.__mutex != (void *) ~0l) +    cond->__data.__mutex = mutex; + +  /* Prepare structure passed to cancellation handler.  */ +  cbuffer.cond = cond; +  cbuffer.mutex = mutex; + +  /* Before we block we enable cancellation.  Therefore we have to +     install a cancellation handler.  */ +  __pthread_cleanup_push (&buffer, __condvar_cleanup, &cbuffer); + +  /* The current values of the wakeup counter.  The "woken" counter +     must exceed this value.  */ +  unsigned long long int val; +  unsigned long long int seq; +  val = seq = cond->__data.__wakeup_seq; +  /* Remember the broadcast counter.  */ +  cbuffer.bc_seq = cond->__data.__broadcast_seq; + +  do +    { +      unsigned int futex_val = cond->__data.__futex; + +      /* Prepare to wait.  Release the condvar futex.  */ +      lll_mutex_unlock (cond->__data.__lock); + +      /* Enable asynchronous cancellation.  Required by the standard.  */ +      cbuffer.oldtype = __pthread_enable_asynccancel (); + +      /* Wait until woken by signal or broadcast.  */ +      lll_futex_wait (&cond->__data.__futex, futex_val); + +      /* Disable asynchronous cancellation.  */ +      __pthread_disable_asynccancel (cbuffer.oldtype); + +      /* We are going to look at shared data again, so get the lock.  */ +      lll_mutex_lock (cond->__data.__lock); + +      /* If a broadcast happened, we are done.  */ +      if (cbuffer.bc_seq != cond->__data.__broadcast_seq) +	goto bc_out; + +      /* Check whether we are eligible for wakeup.  */ +      val = cond->__data.__wakeup_seq; +    } +  while (val == seq || cond->__data.__woken_seq == val); + +  /* Another thread woken up.  */ +  ++cond->__data.__woken_seq; + + bc_out: + +  cond->__data.__nwaiters -= 1 << COND_CLOCK_BITS; + +  /* If pthread_cond_destroy was called on this varaible already, +     notify the pthread_cond_destroy caller all waiters have left +     and it can be successfully destroyed.  */ +  if (cond->__data.__total_seq == -1ULL +      && cond->__data.__nwaiters < (1 << COND_CLOCK_BITS)) +    lll_futex_wake (&cond->__data.__nwaiters, 1); + +  /* We are done with the condvar.  */ +  lll_mutex_unlock (cond->__data.__lock); + +  /* The cancellation handling is back to normal, remove the handler.  */ +  __pthread_cleanup_pop (&buffer, 0); + +  /* Get the mutex before returning.  */ +  return __pthread_mutex_cond_lock (mutex); +} +weak_alias(__pthread_cond_wait, pthread_cond_wait) diff --git a/libpthread/nptl/sysdeps/pthread/pthread_once.c b/libpthread/nptl/sysdeps/pthread/pthread_once.c new file mode 100644 index 000000000..fc16bc535 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_once.c @@ -0,0 +1,54 @@ +/* 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 "pthreadP.h" +#include <lowlevellock.h> + + + +static lll_lock_t once_lock = LLL_LOCK_INITIALIZER; + + +int +__pthread_once ( +     pthread_once_t *once_control, +     void (*init_routine) (void)) +{ +  /* XXX Depending on whether the LOCK_IN_ONCE_T is defined use a +     global lock variable or one which is part of the pthread_once_t +     object.  */ +  if (*once_control == PTHREAD_ONCE_INIT) +    { +      lll_lock (once_lock); + +      /* XXX This implementation is not complete.  It doesn't take +	 cancelation and fork into account.  */ +      if (*once_control == PTHREAD_ONCE_INIT) +	{ +	  init_routine (); + +	  *once_control = !PTHREAD_ONCE_INIT; +	} + +      lll_unlock (once_lock); +    } + +  return 0; +} +strong_alias (__pthread_once, pthread_once) diff --git a/libpthread/nptl/sysdeps/pthread/pthread_rwlock_rdlock.c b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_rdlock.c new file mode 100644 index 000000000..2fdcc49f9 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_rdlock.c @@ -0,0 +1,94 @@ +/* Copyright (C) 2003, 2004 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 <pthread.h> +#include <pthreadP.h> + + +/* Acquire read lock for RWLOCK.  */ +int +__pthread_rwlock_rdlock (pthread_rwlock_t *rwlock) +{ +  int result = 0; + +  /* Make sure we are along.  */ +  lll_mutex_lock (rwlock->__data.__lock); + +  while (1) +    { +      /* Get the rwlock if there is no writer...  */ +      if (rwlock->__data.__writer == 0 +	  /* ...and if either no writer is waiting or we prefer readers.  */ +	  && (!rwlock->__data.__nr_writers_queued +	      || rwlock->__data.__flags == 0)) +	{ +	  /* Increment the reader counter.  Avoid overflow.  */ +	  if (__builtin_expect (++rwlock->__data.__nr_readers == 0, 0)) +	    { +	      /* Overflow on number of readers.	 */ +	      --rwlock->__data.__nr_readers; +	      result = EAGAIN; +	    } + +	  break; +	} + +      /* Make sure we are not holding the rwlock as a writer.  This is +	 a deadlock situation we recognize and report.  */ +      if (__builtin_expect (rwlock->__data.__writer +			    == THREAD_GETMEM (THREAD_SELF, tid), 0)) +	{ +	  result = EDEADLK; +	  break; +	} + +      /* Remember that we are a reader.  */ +      if (__builtin_expect (++rwlock->__data.__nr_readers_queued == 0, 0)) +	{ +	  /* Overflow on number of queued readers.  */ +	  --rwlock->__data.__nr_readers_queued; +	  result = EAGAIN; +	  break; +	} + +      int waitval = rwlock->__data.__readers_wakeup; + +      /* Free the lock.  */ +      lll_mutex_unlock (rwlock->__data.__lock); + +      /* Wait for the writer to finish.  */ +      lll_futex_wait (&rwlock->__data.__readers_wakeup, waitval); + +      /* Get the lock.  */ +      lll_mutex_lock (rwlock->__data.__lock); + +      --rwlock->__data.__nr_readers_queued; +    } + +  /* We are done, free the lock.  */ +  lll_mutex_unlock (rwlock->__data.__lock); + +  return result; +} + +weak_alias (__pthread_rwlock_rdlock, pthread_rwlock_rdlock) +strong_alias (__pthread_rwlock_rdlock, __pthread_rwlock_rdlock_internal) diff --git a/libpthread/nptl/sysdeps/pthread/pthread_rwlock_timedrdlock.c b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_timedrdlock.c new file mode 100644 index 000000000..8503788c2 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_timedrdlock.c @@ -0,0 +1,137 @@ +/* Copyright (C) 2003, 2004 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 <pthread.h> +#include <pthreadP.h> + + +/* Try to acquire read lock for RWLOCK or return after specfied time.  */ +int +pthread_rwlock_timedrdlock ( +     pthread_rwlock_t *rwlock, +     const struct timespec *abstime) +{ +  int result = 0; + +  /* Make sure we are along.  */ +  lll_mutex_lock(rwlock->__data.__lock); + +  while (1) +    { +      int err; + +      /* Get the rwlock if there is no writer...  */ +      if (rwlock->__data.__writer == 0 +	  /* ...and if either no writer is waiting or we prefer readers.  */ +	  && (!rwlock->__data.__nr_writers_queued +	      || rwlock->__data.__flags == 0)) +	{ +	  /* Increment the reader counter.  Avoid overflow.  */ +	  if (++rwlock->__data.__nr_readers == 0) +	    { +	      /* Overflow on number of readers.	 */ +	      --rwlock->__data.__nr_readers; +	      result = EAGAIN; +	    } + +	  break; +	} + +      /* Make sure we are not holding the rwlock as a writer.  This is +	 a deadlock situation we recognize and report.  */ +      if (__builtin_expect (rwlock->__data.__writer +			    == THREAD_GETMEM (THREAD_SELF, tid), 0)) +	{ +	  result = EDEADLK; +	  break; +	} + +      /* Make sure the passed in timeout value is valid.  Ideally this +	 test would be executed once.  But since it must not be +	 performed if we would not block at all simply moving the test +	 to the front is no option.  Replicating all the code is +	 costly while this test is not.  */ +      if (__builtin_expect (abstime->tv_nsec >= 1000000000 +                            || abstime->tv_nsec < 0, 0)) +	{ +	  result = EINVAL; +	  break; +	} + +      /* Get the current time.  So far we support only one clock.  */ +      struct timeval tv; +      (void) gettimeofday (&tv, NULL); + +      /* Convert the absolute timeout value to a relative timeout.  */ +      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; +	} +      /* Did we already time out?  */ +      if (rt.tv_sec < 0) +	{ +	  /* Yep, return with an appropriate error.  */ +	  result = ETIMEDOUT; +	  break; +	} + +      /* Remember that we are a reader.  */ +      if (++rwlock->__data.__nr_readers_queued == 0) +	{ +	  /* Overflow on number of queued readers.  */ +	  --rwlock->__data.__nr_readers_queued; +	  result = EAGAIN; +	  break; +	} + +      int waitval = rwlock->__data.__readers_wakeup; + +      /* Free the lock.  */ +      lll_mutex_unlock (rwlock->__data.__lock); + +      /* Wait for the writer to finish.  */ +      err = lll_futex_timed_wait (&rwlock->__data.__readers_wakeup, +				  waitval, &rt); + +      /* Get the lock.  */ +      lll_mutex_lock (rwlock->__data.__lock); + +      --rwlock->__data.__nr_readers_queued; + +      /* Did the futex call time out?  */ +      if (err == -ETIMEDOUT) +	{ +	  /* Yep, report it.  */ +	  result = ETIMEDOUT; +	  break; +	} +    } + +  /* We are done, free the lock.  */ +  lll_mutex_unlock (rwlock->__data.__lock); + +  return result; +} diff --git a/libpthread/nptl/sysdeps/pthread/pthread_rwlock_timedwrlock.c b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_timedwrlock.c new file mode 100644 index 000000000..d9caa85bb --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_timedwrlock.c @@ -0,0 +1,127 @@ +/* Copyright (C) 2003, 2004 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 <pthread.h> +#include <pthreadP.h> + + +/* Try to acquire write lock for RWLOCK or return after specfied time.	*/ +int +pthread_rwlock_timedwrlock ( +     pthread_rwlock_t *rwlock, +     const struct timespec *abstime) +{ +  int result = 0; + +  /* Make sure we are along.  */ +  lll_mutex_lock (rwlock->__data.__lock); + +  while (1) +    { +      int err; + +      /* Get the rwlock if there is no writer and no reader.  */ +      if (rwlock->__data.__writer == 0 && rwlock->__data.__nr_readers == 0) +	{ +	  /* Mark self as writer.  */ +	  rwlock->__data.__writer = THREAD_GETMEM (THREAD_SELF, tid); +	  break; +	} + +      /* Make sure we are not holding the rwlock as a writer.  This is +	 a deadlock situation we recognize and report.  */ +      if (__builtin_expect (rwlock->__data.__writer +			    == THREAD_GETMEM (THREAD_SELF, tid), 0)) +	{ +	  result = EDEADLK; +	  break; +	} + +      /* Make sure the passed in timeout value is valid.  Ideally this +	 test would be executed once.  But since it must not be +	 performed if we would not block at all simply moving the test +	 to the front is no option.  Replicating all the code is +	 costly while this test is not.  */ +      if (__builtin_expect (abstime->tv_nsec >= 1000000000 +                            || abstime->tv_nsec < 0, 0)) +	{ +	  result = EINVAL; +	  break; +	} + +      /* Get the current time.  So far we support only one clock.  */ +      struct timeval tv; +      (void) gettimeofday (&tv, NULL); + +      /* Convert the absolute timeout value to a relative timeout.  */ +      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; +	} +      /* Did we already time out?  */ +      if (rt.tv_sec < 0) +	{ +	  result = ETIMEDOUT; +	  break; +	} + +      /* Remember that we are a writer.  */ +      if (++rwlock->__data.__nr_writers_queued == 0) +	{ +	  /* Overflow on number of queued writers.  */ +	  --rwlock->__data.__nr_writers_queued; +	  result = EAGAIN; +	  break; +	} + +      int waitval = rwlock->__data.__writer_wakeup; + +      /* Free the lock.  */ +      lll_mutex_unlock (rwlock->__data.__lock); + +      /* Wait for the writer or reader(s) to finish.  */ +      err = lll_futex_timed_wait (&rwlock->__data.__writer_wakeup, +				  waitval, &rt); + +      /* Get the lock.  */ +      lll_mutex_lock (rwlock->__data.__lock); + +      /* To start over again, remove the thread from the writer list.  */ +      --rwlock->__data.__nr_writers_queued; + +      /* Did the futex call time out?  */ +      if (err == -ETIMEDOUT) +	{ +	  result = ETIMEDOUT; +	  break; +	} +    } + +  /* We are done, free the lock.  */ +  lll_mutex_unlock (rwlock->__data.__lock); + +  return result; +} diff --git a/libpthread/nptl/sysdeps/pthread/pthread_rwlock_unlock.c b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_unlock.c new file mode 100644 index 000000000..9cae8b6c2 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_unlock.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2003 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 <pthread.h> +#include <pthreadP.h> + +/* Unlock RWLOCK.  */ +int +__pthread_rwlock_unlock (pthread_rwlock_t *rwlock) +{ +  lll_mutex_lock (rwlock->__data.__lock); +  if (rwlock->__data.__writer) +    rwlock->__data.__writer = 0; +  else +    --rwlock->__data.__nr_readers; +  if (rwlock->__data.__nr_readers == 0) +    { +      if (rwlock->__data.__nr_writers_queued) +	{ +	  ++rwlock->__data.__writer_wakeup; +	  lll_mutex_unlock (rwlock->__data.__lock); +	  lll_futex_wake (&rwlock->__data.__writer_wakeup, 1); +	  return 0; +	} +      else if (rwlock->__data.__nr_readers_queued) +	{ +	  ++rwlock->__data.__readers_wakeup; +	  lll_mutex_unlock (rwlock->__data.__lock); +	  lll_futex_wake (&rwlock->__data.__readers_wakeup, INT_MAX); +	  return 0; +	} +    } +  lll_mutex_unlock (rwlock->__data.__lock); +  return 0; +} + +weak_alias (__pthread_rwlock_unlock, pthread_rwlock_unlock) +strong_alias (__pthread_rwlock_unlock, __pthread_rwlock_unlock_internal) diff --git a/libpthread/nptl/sysdeps/pthread/pthread_rwlock_wrlock.c b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_wrlock.c new file mode 100644 index 000000000..1b9186fb8 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_wrlock.c @@ -0,0 +1,86 @@ +/* Copyright (C) 2003 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 <pthread.h> +#include <pthreadP.h> + + +/* Acquire write lock for RWLOCK.  */ +int +__pthread_rwlock_wrlock (pthread_rwlock_t *rwlock) +{ +  int result = 0; + +  /* Make sure we are along.  */ +  lll_mutex_lock (rwlock->__data.__lock); + +  while (1) +    { +      /* Get the rwlock if there is no writer and no reader.  */ +      if (rwlock->__data.__writer == 0 && rwlock->__data.__nr_readers == 0) +	{ +	  /* Mark self as writer.  */ +	  rwlock->__data.__writer = THREAD_GETMEM (THREAD_SELF, tid); +	  break; +	} + +      /* Make sure we are not holding the rwlock as a writer.  This is +	 a deadlock situation we recognize and report.  */ +      if (__builtin_expect (rwlock->__data.__writer +			    == THREAD_GETMEM (THREAD_SELF, tid), 0)) +	{ +	  result = EDEADLK; +	  break; +	} + +      /* Remember that we are a writer.  */ +      if (++rwlock->__data.__nr_writers_queued == 0) +	{ +	  /* Overflow on number of queued writers.  */ +	  --rwlock->__data.__nr_writers_queued; +	  result = EAGAIN; +	  break; +	} + +      int waitval = rwlock->__data.__writer_wakeup; + +      /* Free the lock.  */ +      lll_mutex_unlock (rwlock->__data.__lock); + +      /* Wait for the writer or reader(s) to finish.  */ +      lll_futex_wait (&rwlock->__data.__writer_wakeup, waitval); + +      /* Get the lock.  */ +      lll_mutex_lock (rwlock->__data.__lock); + +      /* To start over again, remove the thread from the writer list.  */ +      --rwlock->__data.__nr_writers_queued; +    } + +  /* We are done, free the lock.  */ +  lll_mutex_unlock (rwlock->__data.__lock); + +  return result; +} + +weak_alias (__pthread_rwlock_wrlock, pthread_rwlock_wrlock) +strong_alias (__pthread_rwlock_wrlock, __pthread_rwlock_wrlock_internal) diff --git a/libpthread/nptl/sysdeps/pthread/pthread_sigmask.c b/libpthread/nptl/sysdeps/pthread/pthread_sigmask.c new file mode 100644 index 000000000..6f66bbbff --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_sigmask.c @@ -0,0 +1,58 @@ +/* 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 <signal.h> +#include <pthreadP.h> +#include <sysdep.h> + + +int +pthread_sigmask ( +     int how, +     const sigset_t *newmask, +     sigset_t *oldmask) +{ +  sigset_t local_newmask; + +  /* The only thing we have to make sure here is that SIGCANCEL and +     SIGSETXID is not blocked.  */ +  if (newmask != NULL +      && (__builtin_expect (__sigismember (newmask, SIGCANCEL), 0) +	  || __builtin_expect (__sigismember (newmask, SIGSETXID), 0))) +    { +      local_newmask = *newmask; +      __sigdelset (&local_newmask, SIGCANCEL); +      __sigdelset (&local_newmask, SIGSETXID); +      newmask = &local_newmask; +    } + +#ifdef INTERNAL_SYSCALL +  /* We know that realtime signals are available if NPTL is used.  */ +  INTERNAL_SYSCALL_DECL (err); +  int result = INTERNAL_SYSCALL (rt_sigprocmask, err, 4, how, newmask, +				 oldmask, _NSIG / 8); + +  return (INTERNAL_SYSCALL_ERROR_P (result, err) +	  ? INTERNAL_SYSCALL_ERRNO (result, err) +	  : 0); +#else +  return sigprocmask (how, newmask, oldmask) == -1 ? errno : 0; +#endif +} diff --git a/libpthread/nptl/sysdeps/pthread/pthread_spin_destroy.c b/libpthread/nptl/sysdeps/pthread/pthread_spin_destroy.c new file mode 100644 index 000000000..62082f44e --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_spin_destroy.c @@ -0,0 +1,28 @@ +/* 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 "pthreadP.h" + + +int +pthread_spin_destroy (pthread_spinlock_t *lock) +{ +  /* Nothing to do.  */ +  return 0; +} diff --git a/libpthread/nptl/sysdeps/pthread/pthread_spin_init.c b/libpthread/nptl/sysdeps/pthread/pthread_spin_init.c new file mode 100644 index 000000000..c2275085e --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_spin_init.c @@ -0,0 +1,28 @@ +/* pthread_spin_init -- initialize a spin lock.  Generic 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 "pthreadP.h" + +int +pthread_spin_init (pthread_spinlock_t *lock, int pshared) +{ +  *lock = 0; +  return 0; +} diff --git a/libpthread/nptl/sysdeps/pthread/pthread_spin_unlock.c b/libpthread/nptl/sysdeps/pthread/pthread_spin_unlock.c new file mode 100644 index 000000000..f97cadfbd --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_spin_unlock.c @@ -0,0 +1,30 @@ +/* pthread_spin_unlock -- unlock a spin lock.  Generic 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 "pthreadP.h" +#include <atomic.h> + +int +pthread_spin_unlock (pthread_spinlock_t *lock) +{ +  atomic_full_barrier (); +  *lock = 0; +  return 0; +} diff --git a/libpthread/nptl/sysdeps/pthread/rt-unwind-resume.c b/libpthread/nptl/sysdeps/pthread/rt-unwind-resume.c new file mode 100644 index 000000000..743e675d4 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/rt-unwind-resume.c @@ -0,0 +1 @@ +#include <unwind-resume.c> diff --git a/libpthread/nptl/sysdeps/pthread/setxid.h b/libpthread/nptl/sysdeps/pthread/setxid.h new file mode 100644 index 000000000..8ec382f40 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/setxid.h @@ -0,0 +1,64 @@ +/* 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 <pthreadP.h> +#include <sysdep.h> + +#define __SETXID_1(cmd, arg1) \ +  cmd.id[0] = arg1 +#define __SETXID_2(cmd, arg1, arg2) \ +  __SETXID_1 (cmd, arg1); cmd.id[1] = arg2 +#define __SETXID_3(cmd, arg1, arg2, arg3) \ +  __SETXID_2 (cmd, arg1, arg2); cmd.id[2] = arg3 + +#ifdef SINGLE_THREAD +# define INLINE_SETXID_SYSCALL(name, nr, args...) \ +  INLINE_SYSCALL (name, nr, args) +#elif defined SHARED +# define INLINE_SETXID_SYSCALL(name, nr, args...) \ +  ({									\ +    int __result;							\ +    if (__builtin_expect (__libc_pthread_functions.ptr__nptl_setxid	\ +			  != NULL, 0))					\ +      {									\ +	struct xid_command __cmd;					\ +	__cmd.syscall_no = __NR_##name;					\ +	__SETXID_##nr (__cmd, args);					\ +	__result = __libc_pthread_functions.ptr__nptl_setxid (&__cmd);	\ +	}								\ +    else								\ +      __result = INLINE_SYSCALL (name, nr, args);			\ +    __result;								\ +   }) +#else +# define INLINE_SETXID_SYSCALL(name, nr, args...) \ +  ({									\ +    extern __typeof (__nptl_setxid) __nptl_setxid __attribute__((weak));\ +    int __result;							\ +    if (__builtin_expect (__nptl_setxid	!= NULL, 0))			\ +      {									\ +	struct xid_command __cmd;					\ +	__cmd.syscall_no = __NR_##name;					\ +	__SETXID_##nr (__cmd, args);					\ +	__result =__nptl_setxid (&__cmd);				\ +      }									\ +    else								\ +      __result = INLINE_SYSCALL (name, nr, args);			\ +    __result;								\ +   }) +#endif diff --git a/libpthread/nptl/sysdeps/pthread/sigaction.c b/libpthread/nptl/sysdeps/pthread/sigaction.c new file mode 100644 index 000000000..54b5d2de4 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/sigaction.c @@ -0,0 +1,54 @@ +/* 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.  */ + +/* This is tricky.  GCC doesn't like #include_next in the primary +   source file and even if it did, the first #include_next is this +   exact file anyway.  */ +#ifndef LIBC_SIGACTION + +#include <pthreadP.h> + +/* We use the libc implementation but we tell it to not allow +   SIGCANCEL or SIGTIMER to be handled.  */ +# define LIBC_SIGACTION	1 + +# include <sigaction.c> + +int +sigaction (int sig, const struct sigaction *act, struct sigaction *oact); + +int +__sigaction (int sig, const struct sigaction *act, struct sigaction *oact) +{ +  if (__builtin_expect (sig == SIGCANCEL || sig == SIGSETXID, 0)) +    { +      __set_errno (EINVAL); +      return -1; +    } + +  return __libc_sigaction (sig, act, oact); +} +libc_hidden_proto(sigaction) +weak_alias (__sigaction, sigaction) +libc_hidden_weak(sigaction) +#else + +# include_next <sigaction.c> + +#endif /* LIBC_SIGACTION */ diff --git a/libpthread/nptl/sysdeps/pthread/sigfillset.c b/libpthread/nptl/sysdeps/pthread/sigfillset.c new file mode 100644 index 000000000..fbe458f55 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/sigfillset.c @@ -0,0 +1,21 @@ +/* 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 <pthreadP.h> + +#include <../../../../libc/signal/sigfillset.c> diff --git a/libpthread/nptl/sysdeps/pthread/sigprocmask.c b/libpthread/nptl/sysdeps/pthread/sigprocmask.c new file mode 100644 index 000000000..35aa843ba --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/sigprocmask.c @@ -0,0 +1,22 @@ +/* Copyright (C) 1997,1998,1999,2000,2001,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 <pthreadP.h> +#undef _LARGEFILE64_SOURCE + +#include <../../../../libc/sysdeps/linux/common/sigprocmask.c> diff --git a/libpthread/nptl/sysdeps/pthread/timer_create.c b/libpthread/nptl/sysdeps/pthread/timer_create.c new file mode 100644 index 000000000..ae82c5af0 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/timer_create.c @@ -0,0 +1,170 @@ +/* Copyright (C) 2000, 2003, 2004 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General 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 <signal.h> +#include <pthread.h> +#include <time.h> +#include <unistd.h> + +#include "posix-timer.h" + + +/* Create new per-process timer using CLOCK.  */ +int +timer_create ( +     clockid_t clock_id, +     struct sigevent *evp, +     timer_t *timerid) +{ +  int retval = -1; +  struct timer_node *newtimer = NULL; +  struct thread_node *thread = NULL; + +  if (0 +#if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0 +      || clock_id == CLOCK_PROCESS_CPUTIME_ID +#endif +#if defined _POSIX_THREAD_CPUTIME && _POSIX_THREAD_CPUTIME >= 0 +      || clock_id == CLOCK_THREAD_CPUTIME_ID +#endif +      ) +    { +      /* We don't allow timers for CPU clocks.  At least not in the +	 moment.  */ +      __set_errno (ENOTSUP); +      return -1; +    } + +  if (clock_id != CLOCK_REALTIME) +    { +      __set_errno (EINVAL); +      return -1; +    } + +  pthread_once (&__timer_init_once_control, __timer_init_once); + +  if (__timer_init_failed) +    { +      __set_errno (ENOMEM); +      return -1; +    } + +  pthread_mutex_lock (&__timer_mutex); + +  newtimer = __timer_alloc (); +  if (__builtin_expect (newtimer == NULL, 0)) +    { +      __set_errno (EAGAIN); +      goto unlock_bail; +    } + +  if (evp != NULL) +    newtimer->event = *evp; +  else +    { +      newtimer->event.sigev_notify = SIGEV_SIGNAL; +      newtimer->event.sigev_signo = SIGALRM; +      newtimer->event.sigev_value.sival_ptr = timer_ptr2id (newtimer); +      newtimer->event.sigev_notify_function = 0; +    } + +  newtimer->event.sigev_notify_attributes = &newtimer->attr; +  newtimer->creator_pid = getpid (); + +  switch (__builtin_expect (newtimer->event.sigev_notify, SIGEV_SIGNAL)) +    { +    case SIGEV_NONE: +    case SIGEV_SIGNAL: +      /* We have a global thread for delivering timed signals. +	 If it is not running, try to start it up.  */ +      thread = &__timer_signal_thread_rclk; +      if (! thread->exists) +	{ +	  if (__builtin_expect (__timer_thread_start (thread), +				1) < 0) +	    { +	      __set_errno (EAGAIN); +	      goto unlock_bail; +            } +        } +      break; + +    case SIGEV_THREAD: +      /* Copy over thread attributes or set up default ones.  */ +      if (evp->sigev_notify_attributes) +	newtimer->attr = *(pthread_attr_t *) evp->sigev_notify_attributes; +      else +	pthread_attr_init (&newtimer->attr); + +      /* Ensure thread attributes call for deatched thread.  */ +      pthread_attr_setdetachstate (&newtimer->attr, PTHREAD_CREATE_DETACHED); + +      /* Try to find existing thread having the right attributes.  */ +      thread = __timer_thread_find_matching (&newtimer->attr, clock_id); + +      /* If no existing thread has these attributes, try to allocate one.  */ +      if (thread == NULL) +	thread = __timer_thread_alloc (&newtimer->attr, clock_id); + +      /* Out of luck; no threads are available.  */ +      if (__builtin_expect (thread == NULL, 0)) +	{ +	  __set_errno (EAGAIN); +	  goto unlock_bail; +	} + +      /* If the thread is not running already, try to start it.  */ +      if (! thread->exists +	  && __builtin_expect (! __timer_thread_start (thread), 0)) +	{ +	  __set_errno (EAGAIN); +	  goto unlock_bail; +	} +      break; + +    default: +      __set_errno (EINVAL); +      goto unlock_bail; +    } + +  newtimer->clock = clock_id; +  newtimer->abstime = 0; +  newtimer->armed = 0; +  newtimer->thread = thread; + +  *timerid = timer_ptr2id (newtimer); +  retval = 0; + +  if (__builtin_expect (retval, 0) == -1) +    { +    unlock_bail: +      if (thread != NULL) +	__timer_thread_dealloc (thread); +      if (newtimer != NULL) +	{ +	  timer_delref (newtimer); +	  __timer_dealloc (newtimer); +	} +    } + +  pthread_mutex_unlock (&__timer_mutex); + +  return retval; +} diff --git a/libpthread/nptl/sysdeps/pthread/timer_delete.c b/libpthread/nptl/sysdeps/pthread/timer_delete.c new file mode 100644 index 000000000..4c53112db --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/timer_delete.c @@ -0,0 +1,70 @@ +/* Copyright (C) 2000, 2001 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General 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 <assert.h> +#include <errno.h> +#include <pthread.h> +#include <time.h> + +#include "posix-timer.h" + + +/* Delete timer TIMERID.  */ +int +timer_delete ( +     timer_t timerid) +{ +  struct timer_node *timer; +  int retval = -1; + +  pthread_mutex_lock (&__timer_mutex); + +  timer = timer_id2ptr (timerid); +  if (! timer_valid (timer)) +    /* Invalid timer ID or the timer is not in use.  */ +    __set_errno (EINVAL); +  else +    { +      if (timer->armed && timer->thread != NULL) +	{ +	  struct thread_node *thread = timer->thread; +	  assert (thread != NULL); + +	  /* If thread is cancelled while waiting for handler to terminate, +	     the mutex is unlocked and timer_delete is aborted.  */ +	  pthread_cleanup_push (__timer_mutex_cancel_handler, &__timer_mutex); + +	  /* If timer is currently being serviced, wait for it to finish.  */ +	  while (thread->current_timer == timer) +	    pthread_cond_wait (&thread->cond, &__timer_mutex); + +	  pthread_cleanup_pop (0); +        } + +      /* Remove timer from whatever queue it may be on and deallocate it.  */ +      timer->inuse = TIMER_DELETED; +      list_unlink_ip (&timer->links); +      timer_delref (timer); +      retval = 0; +    } + +  pthread_mutex_unlock (&__timer_mutex); + +  return retval; +} diff --git a/libpthread/nptl/sysdeps/pthread/timer_getoverr.c b/libpthread/nptl/sysdeps/pthread/timer_getoverr.c new file mode 100644 index 000000000..f3e22215b --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/timer_getoverr.c @@ -0,0 +1,45 @@ +/* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General 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 <time.h> + +#include "posix-timer.h" + + +/* Get expiration overrun for timer TIMERID.  */ +int +timer_getoverrun (timerid) +     timer_t timerid; +{ +  struct timer_node *timer; +  int retval = -1; + +  pthread_mutex_lock (&__timer_mutex); + +  if (! timer_valid (timer = timer_id2ptr (timerid))) +    __set_errno (EINVAL); +  else +    retval = timer->overrun_count; + +  pthread_mutex_unlock (&__timer_mutex); + +  return retval; +} diff --git a/libpthread/nptl/sysdeps/pthread/timer_gettime.c b/libpthread/nptl/sysdeps/pthread/timer_gettime.c new file mode 100644 index 000000000..723a61632 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/timer_gettime.c @@ -0,0 +1,77 @@ +/* Copyright (C) 2000, 2004 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General 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 <time.h> + +#include "posix-timer.h" + + +/* Get current value of timer TIMERID and store it in VLAUE.  */ +int +timer_gettime (timerid, value) +     timer_t timerid; +     struct itimerspec *value; +{ +  struct timer_node *timer; +  struct timespec now, expiry; +  int retval = -1, armed = 0, valid; +  clock_t clock = 0; + +  pthread_mutex_lock (&__timer_mutex); + +  timer = timer_id2ptr (timerid); +  valid = timer_valid (timer); + +  if (valid) { +    armed = timer->armed; +    expiry = timer->expirytime; +    clock = timer->clock; +    value->it_interval = timer->value.it_interval; +  } + +  pthread_mutex_unlock (&__timer_mutex); + +  if (valid) +    { +      if (armed) +	{ +	  clock_gettime (clock, &now); +	  if (timespec_compare (&now, &expiry) < 0) +	    timespec_sub (&value->it_value, &expiry, &now); +	  else +	    { +	      value->it_value.tv_sec = 0; +	      value->it_value.tv_nsec = 0; +	    } +	} +      else +	{ +	  value->it_value.tv_sec = 0; +	  value->it_value.tv_nsec = 0; +	} + +      retval = 0; +    } +  else +    __set_errno (EINVAL); + +  return retval; +} diff --git a/libpthread/nptl/sysdeps/pthread/timer_routines.c b/libpthread/nptl/sysdeps/pthread/timer_routines.c new file mode 100644 index 000000000..8d5b1d13a --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/timer_routines.c @@ -0,0 +1,578 @@ +/* Helper code for POSIX timer implementation on NPTL. +   Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General 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 <assert.h> +#include <errno.h> +#include <pthread.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <sysdep.h> +#include <time.h> +#include <unistd.h> +#include <sys/syscall.h> + +#include "posix-timer.h" +#include <pthreadP.h> + + +/* Number of threads used.  */ +#define THREAD_MAXNODES	16 + +/* Array containing the descriptors for the used threads.  */ +static struct thread_node thread_array[THREAD_MAXNODES]; + +/* Static array with the structures for all the timers.  */ +struct timer_node __timer_array[TIMER_MAX]; + +/* Global lock to protect operation on the lists.  */ +pthread_mutex_t __timer_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* Variable to protext initialization.  */ +pthread_once_t __timer_init_once_control = PTHREAD_ONCE_INIT; + +/* Nonzero if initialization of timer implementation failed.  */ +int __timer_init_failed; + +/* Node for the thread used to deliver signals.  */ +struct thread_node __timer_signal_thread_rclk; + +/* Lists to keep free and used timers and threads.  */ +struct list_links timer_free_list; +struct list_links thread_free_list; +struct list_links thread_active_list; + + +#ifdef __NR_rt_sigqueueinfo +extern int __syscall_rt_sigqueueinfo (int, int, siginfo_t *); +#endif + + +/* List handling functions.  */ +static inline void +list_init (struct list_links *list) +{ +  list->next = list->prev = list; +} + +static inline void +list_append (struct list_links *list, struct list_links *newp) +{ +  newp->prev = list->prev; +  newp->next = list; +  list->prev->next = newp; +  list->prev = newp; +} + +static inline void +list_insbefore (struct list_links *list, struct list_links *newp) +{ +  list_append (list, newp); +} + +/* + * Like list_unlink_ip, except that calling it on a node that + * is already unlinked is disastrous rather than a noop. + */ + +static inline void +list_unlink (struct list_links *list) +{ +  struct list_links *lnext = list->next, *lprev = list->prev; + +  lnext->prev = lprev; +  lprev->next = lnext; +} + +static inline struct list_links * +list_first (struct list_links *list) +{ +  return list->next; +} + +static inline struct list_links * +list_null (struct list_links *list) +{ +  return list; +} + +static inline struct list_links * +list_next (struct list_links *list) +{ +  return list->next; +} + +static inline int +list_isempty (struct list_links *list) +{ +  return list->next == list; +} + + +/* Functions build on top of the list functions.  */ +static inline struct thread_node * +thread_links2ptr (struct list_links *list) +{ +  return (struct thread_node *) ((char *) list +				 - offsetof (struct thread_node, links)); +} + +static inline struct timer_node * +timer_links2ptr (struct list_links *list) +{ +  return (struct timer_node *) ((char *) list +				- offsetof (struct timer_node, links)); +} + + +/* Initialize a newly allocated thread structure.  */ +static void +thread_init (struct thread_node *thread, const pthread_attr_t *attr, clockid_t clock_id) +{ +  if (attr != NULL) +    thread->attr = *attr; +  else +    { +      pthread_attr_init (&thread->attr); +      pthread_attr_setdetachstate (&thread->attr, PTHREAD_CREATE_DETACHED); +    } + +  thread->exists = 0; +  list_init (&thread->timer_queue); +  pthread_cond_init (&thread->cond, 0); +  thread->current_timer = 0; +  thread->captured = pthread_self (); +  thread->clock_id = clock_id; +} + + +/* Initialize the global lists, and acquire global resources.  Error +   reporting is done by storing a non-zero value to the global variable +   timer_init_failed.  */ +static void +init_module (void) +{ +  int i; + +  list_init (&timer_free_list); +  list_init (&thread_free_list); +  list_init (&thread_active_list); + +  for (i = 0; i < TIMER_MAX; ++i) +    { +      list_append (&timer_free_list, &__timer_array[i].links); +      __timer_array[i].inuse = TIMER_FREE; +    } + +  for (i = 0; i < THREAD_MAXNODES; ++i) +    list_append (&thread_free_list, &thread_array[i].links); + +  thread_init (&__timer_signal_thread_rclk, 0, CLOCK_REALTIME); +} + + +/* This is a handler executed in a child process after a fork() +   occurs.  It reinitializes the module, resetting all of the data +   structures to their initial state.  The mutex is initialized in +   case it was locked in the parent process.  */ +static void +reinit_after_fork (void) +{ +  init_module (); +  pthread_mutex_init (&__timer_mutex, 0); +} + + +/* Called once form pthread_once in timer_init. This initializes the +   module and ensures that reinit_after_fork will be executed in any +   child process.  */ +void +__timer_init_once (void) +{ +  init_module (); +  pthread_atfork (0, 0, reinit_after_fork); +} + + +/* Deinitialize a thread that is about to be deallocated.  */ +static void +thread_deinit (struct thread_node *thread) +{ +  assert (list_isempty (&thread->timer_queue)); +  pthread_cond_destroy (&thread->cond); +} + + +/* Allocate a thread structure from the global free list.  Global +   mutex lock must be held by caller.  The thread is moved to +   the active list. */ +struct thread_node * +__timer_thread_alloc (const pthread_attr_t *desired_attr, clockid_t clock_id) +{ +  struct list_links *node = list_first (&thread_free_list); + +  if (node != list_null (&thread_free_list)) +    { +      struct thread_node *thread = thread_links2ptr (node); +      list_unlink (node); +      thread_init (thread, desired_attr, clock_id); +      list_append (&thread_active_list, node); +      return thread; +    } + +  return 0; +} + + +/* Return a thread structure to the global free list.  Global lock +   must be held by caller.  */ +void +__timer_thread_dealloc (struct thread_node *thread) +{ +  thread_deinit (thread); +  list_unlink (&thread->links); +  list_append (&thread_free_list, &thread->links); +} + + +/* Each of our threads which terminates executes this cleanup +   handler. We never terminate threads ourselves; if a thread gets here +   it means that the evil application has killed it.  If the thread has +   timers, these require servicing and so we must hire a replacement +   thread right away.  We must also unblock another thread that may +   have been waiting for this thread to finish servicing a timer (see +   timer_delete()).  */ + +static void +thread_cleanup (void *val) +{ +  if (val != NULL) +    { +      struct thread_node *thread = val; + +      /* How did the signal thread get killed?  */ +      assert (thread != &__timer_signal_thread_rclk); + +      pthread_mutex_lock (&__timer_mutex); + +      thread->exists = 0; + +      /* We are no longer processing a timer event.  */ +      thread->current_timer = 0; + +      if (list_isempty (&thread->timer_queue)) +	__timer_thread_dealloc (thread); +      else +	(void) __timer_thread_start (thread); + +      pthread_mutex_unlock (&__timer_mutex); + +      /* Unblock potentially blocked timer_delete().  */ +      pthread_cond_broadcast (&thread->cond); +    } +} + + +/* Handle a timer which is supposed to go off now.  */ +static void +thread_expire_timer (struct thread_node *self, struct timer_node *timer) +{ +  self->current_timer = timer; /* Lets timer_delete know timer is running. */ + +  pthread_mutex_unlock (&__timer_mutex); + +  switch (__builtin_expect (timer->event.sigev_notify, SIGEV_SIGNAL)) +    { +    case SIGEV_NONE: +      break; + +    case SIGEV_SIGNAL: +#ifdef __NR_rt_sigqueueinfo +      { +	siginfo_t info; + +	/* First, clear the siginfo_t structure, so that we don't pass our +	   stack content to other tasks.  */ +	memset (&info, 0, sizeof (siginfo_t)); +	/* We must pass the information about the data in a siginfo_t +           value.  */ +	info.si_signo = timer->event.sigev_signo; +	info.si_code = SI_TIMER; +	info.si_pid = timer->creator_pid; +	info.si_uid = getuid (); +	info.si_value = timer->event.sigev_value; + +	INLINE_SYSCALL (rt_sigqueueinfo, 3, info.si_pid, info.si_signo, &info); +      } +#else +      if (pthread_kill (self->captured, timer->event.sigev_signo) != 0) +	{ +	  if (pthread_kill (self->id, timer->event.sigev_signo) != 0) +	    abort (); +        } +#endif +      break; + +    case SIGEV_THREAD: +      timer->event.sigev_notify_function (timer->event.sigev_value); +      break; + +    default: +      assert (! "unknown event"); +      break; +    } + +  pthread_mutex_lock (&__timer_mutex); + +  self->current_timer = 0; + +  pthread_cond_broadcast (&self->cond); +} + + +/* Thread function; executed by each timer thread. The job of this +   function is to wait on the thread's timer queue and expire the +   timers in chronological order as close to their scheduled time as +   possible.  */ +static void +__attribute__ ((noreturn)) +thread_func (void *arg) +{ +  struct thread_node *self = arg; + +  /* Register cleanup handler, in case rogue application terminates +     this thread.  (This cannot happen to __timer_signal_thread, which +     doesn't invoke application callbacks). */ + +  pthread_cleanup_push (thread_cleanup, self); + +  pthread_mutex_lock (&__timer_mutex); + +  while (1) +    { +      struct list_links *first; +      struct timer_node *timer = NULL; + +      /* While the timer queue is not empty, inspect the first node.  */ +      first = list_first (&self->timer_queue); +      if (first != list_null (&self->timer_queue)) +	{ +	  struct timespec now; + +	  timer = timer_links2ptr (first); + +	  /* This assumes that the elements of the list of one thread +	     are all for the same clock.  */ +	  clock_gettime (timer->clock, &now); + +	  while (1) +	    { +	      /* If the timer is due or overdue, remove it from the queue. +		 If it's a periodic timer, re-compute its new time and +		 requeue it.  Either way, perform the timer expiry. */ +	      if (timespec_compare (&now, &timer->expirytime) < 0) +		break; + +	      list_unlink_ip (first); + +	      if (__builtin_expect (timer->value.it_interval.tv_sec, 0) != 0 +		  || timer->value.it_interval.tv_nsec != 0) +		{ +		  timer->overrun_count = 0; +		  timespec_add (&timer->expirytime, &timer->expirytime, +				&timer->value.it_interval); +		  while (timespec_compare (&timer->expirytime, &now) < 0) +		    { +		      timespec_add (&timer->expirytime, &timer->expirytime, +				    &timer->value.it_interval); +		      if (timer->overrun_count < DELAYTIMER_MAX) +			++timer->overrun_count; +		    } +		  __timer_thread_queue_timer (self, timer); +		} + +	      thread_expire_timer (self, timer); + +	      first = list_first (&self->timer_queue); +	      if (first == list_null (&self->timer_queue)) +		break; + +	      timer = timer_links2ptr (first); +	    } +	} + +      /* If the queue is not empty, wait until the expiry time of the +	 first node.  Otherwise wait indefinitely.  Insertions at the +	 head of the queue must wake up the thread by broadcasting +	 this condition variable.  */ +      if (timer != NULL) +	pthread_cond_timedwait (&self->cond, &__timer_mutex, +				&timer->expirytime); +      else +	pthread_cond_wait (&self->cond, &__timer_mutex); +    } +  /* This macro will never be executed since the while loop loops +     forever - but we have to add it for proper nesting.  */ +  pthread_cleanup_pop (1); +} + + +/* Enqueue a timer in wakeup order in the thread's timer queue. +   Returns 1 if the timer was inserted at the head of the queue, +   causing the queue's next wakeup time to change. */ + +int +__timer_thread_queue_timer (struct thread_node *thread, +			    struct timer_node *insert) +{ +  struct list_links *iter; +  int athead = 1; + +  for (iter = list_first (&thread->timer_queue); +       iter != list_null (&thread->timer_queue); +        iter = list_next (iter)) +    { +      struct timer_node *timer = timer_links2ptr (iter); + +      if (timespec_compare (&insert->expirytime, &timer->expirytime) < 0) +	  break; +      athead = 0; +    } + +  list_insbefore (iter, &insert->links); +  return athead; +} + + +/* Start a thread and associate it with the given thread node.  Global +   lock must be held by caller.  */ +int +__timer_thread_start (struct thread_node *thread) +{ +  int retval = 1; + +  assert (!thread->exists); +  thread->exists = 1; + +  if (pthread_create (&thread->id, &thread->attr, +		      (void *(*) (void *)) thread_func, thread) != 0) +    { +      thread->exists = 0; +      retval = -1; +    } + +  return retval; +} + + +void +__timer_thread_wakeup (struct thread_node *thread) +{ +  pthread_cond_broadcast (&thread->cond); +} + + +/* Compare two pthread_attr_t thread attributes for exact equality. +   Returns 1 if they are equal, otherwise zero if they are not equal +   or contain illegal values.  This version is NPTL-specific for +   performance reason.  One could use the access functions to get the +   values of all the fields of the attribute structure.  */ +static int +thread_attr_compare (const pthread_attr_t *left, const pthread_attr_t *right) +{ +  struct pthread_attr *ileft = (struct pthread_attr *) left; +  struct pthread_attr *iright = (struct pthread_attr *) right; + +  return (ileft->flags == iright->flags +	  && ileft->schedpolicy == iright->schedpolicy +	  && (ileft->schedparam.sched_priority +	      == iright->schedparam.sched_priority) +	  && ileft->guardsize == iright->guardsize +	  && ileft->stackaddr == iright->stackaddr +	  && ileft->stacksize == iright->stacksize +	  && ((ileft->cpuset == NULL && iright->cpuset == NULL) +	      || (ileft->cpuset != NULL && iright->cpuset != NULL +		  && ileft->cpusetsize == iright->cpusetsize +		  && memcmp (ileft->cpuset, iright->cpuset, +			     ileft->cpusetsize) == 0))); +} + + +/* Search the list of active threads and find one which has matching +   attributes.  Global mutex lock must be held by caller.  */ +struct thread_node * +__timer_thread_find_matching (const pthread_attr_t *desired_attr, +			      clockid_t desired_clock_id) +{ +  struct list_links *iter = list_first (&thread_active_list); + +  while (iter != list_null (&thread_active_list)) +    { +      struct thread_node *candidate = thread_links2ptr (iter); + +      if (thread_attr_compare (desired_attr, &candidate->attr) +	  && desired_clock_id == candidate->clock_id) +	return candidate; + +      iter = list_next (iter); +    } + +  return NULL; +} + + +/* Grab a free timer structure from the global free list.  The global +   lock must be held by the caller.  */ +struct timer_node * +__timer_alloc (void) +{ +  struct list_links *node = list_first (&timer_free_list); + +  if (node != list_null (&timer_free_list)) +    { +      struct timer_node *timer = timer_links2ptr (node); +      list_unlink_ip (node); +      timer->inuse = TIMER_INUSE; +      timer->refcount = 1; +      return timer; +    } + +  return NULL; +} + + +/* Return a timer structure to the global free list.  The global lock +   must be held by the caller.  */ +void +__timer_dealloc (struct timer_node *timer) +{ +  assert (timer->refcount == 0); +  timer->thread = NULL;	/* Break association between timer and thread.  */ +  timer->inuse = TIMER_FREE; +  list_append (&timer_free_list, &timer->links); +} + + +/* Thread cancellation handler which unlocks a mutex.  */ +void +__timer_mutex_cancel_handler (void *arg) +{ +  pthread_mutex_unlock (arg); +} diff --git a/libpthread/nptl/sysdeps/pthread/timer_settime.c b/libpthread/nptl/sysdeps/pthread/timer_settime.c new file mode 100644 index 000000000..592b5271b --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/timer_settime.c @@ -0,0 +1,137 @@ +/* Copyright (C) 2000, 2001 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public License as +   published by the Free Software Foundation; either version 2.1 of the +   License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General 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 <time.h> + +#include "posix-timer.h" + + +/* Set timer TIMERID to VALUE, returning old value in OVLAUE.  */ +int +timer_settime (timerid, flags, value, ovalue) +     timer_t timerid; +     int flags; +     const struct itimerspec *value; +     struct itimerspec *ovalue; +{ +  struct timer_node *timer; +  struct thread_node *thread = NULL; +  struct timespec now; +  int have_now = 0, need_wakeup = 0; +  int retval = -1; + +  timer = timer_id2ptr (timerid); +  if (timer == NULL) +    { +      __set_errno (EINVAL); +      goto bail; +    } + +  if (value->it_interval.tv_nsec < 0 +      || value->it_interval.tv_nsec >= 1000000000 +      || value->it_value.tv_nsec < 0 +      || value->it_value.tv_nsec >= 1000000000) +    { +      __set_errno (EINVAL); +      goto bail; +    } + +  /* Will need to know current time since this is a relative timer; +     might as well make the system call outside of the lock now! */ + +  if ((flags & TIMER_ABSTIME) == 0) +    { +      clock_gettime (timer->clock, &now); +      have_now = 1; +    } + +  pthread_mutex_lock (&__timer_mutex); +  timer_addref (timer); + +  /* One final check of timer validity; this one is possible only +     until we have the mutex, because it accesses the inuse flag. */ + +  if (! timer_valid(timer)) +    { +      __set_errno (EINVAL); +      goto unlock_bail; +    } + +  if (ovalue != NULL) +    { +      ovalue->it_interval = timer->value.it_interval; + +      if (timer->armed) +	{ +	  if (! have_now) +	    { +	      pthread_mutex_unlock (&__timer_mutex); +	      clock_gettime (timer->clock, &now); +	      have_now = 1; +	      pthread_mutex_lock (&__timer_mutex); +	      timer_addref (timer); +	    } + +	  timespec_sub (&ovalue->it_value, &timer->expirytime, &now); +	} +      else +	{ +	  ovalue->it_value.tv_sec = 0; +	  ovalue->it_value.tv_nsec = 0; +	} +    } + +  timer->value = *value; + +  list_unlink_ip (&timer->links); +  timer->armed = 0; + +  thread = timer->thread; + +  /* A value of { 0, 0 } causes the timer to be stopped. */ +  if (value->it_value.tv_sec != 0 +      || __builtin_expect (value->it_value.tv_nsec != 0, 1)) +    { +      if ((flags & TIMER_ABSTIME) != 0) +	/* The user specified the expiration time.  */ +	timer->expirytime = value->it_value; +      else +	timespec_add (&timer->expirytime, &now, &value->it_value); + +      /* Only need to wake up the thread if timer is inserted +	 at the head of the queue. */ +      if (thread != NULL) +	need_wakeup = __timer_thread_queue_timer (thread, timer); +      timer->armed = 1; +    } + +  retval = 0; + +unlock_bail: +  timer_delref (timer); +  pthread_mutex_unlock (&__timer_mutex); + +bail: +  if (thread != NULL && need_wakeup) +    __timer_thread_wakeup (thread); + +  return retval; +} diff --git a/libpthread/nptl/sysdeps/pthread/unwind-forcedunwind.c b/libpthread/nptl/sysdeps/pthread/unwind-forcedunwind.c new file mode 100644 index 000000000..8b1f24407 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/unwind-forcedunwind.c @@ -0,0 +1,103 @@ +/* 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> +#include <pthreadP.h> + +#define __libc_dlopen(x)	dlopen(x, (RTLD_LOCAL | RTLD_LAZY)) +#define __libc_dlsym		dlsym + +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 *); + +void +pthread_cancel_init (void) +{ +  void *resume, *personality, *forcedunwind, *getcfa; +  void *handle; + +  if (__builtin_expect (libgcc_s_getcfa != NULL, 1)) +    return; + +  handle = __libc_dlopen ("libgcc_s.so.1"); + +  if (handle == NULL +      || (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL +      || (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL +      || (forcedunwind = __libc_dlsym (handle, "_Unwind_ForcedUnwind")) +	 == NULL +      || (getcfa = __libc_dlsym (handle, "_Unwind_GetCFA")) == NULL +#ifdef ARCH_CANCEL_INIT +      || ARCH_CANCEL_INIT (handle) +#endif +      ) +  { +    printf("libgcc_s.so.1 must be installed for pthread_cancel to work\n"); +    abort(); +  } + +  libgcc_s_resume = resume; +  libgcc_s_personality = personality; +  libgcc_s_forcedunwind = forcedunwind; +  libgcc_s_getcfa = getcfa; +} + +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); +} diff --git a/libpthread/nptl/sysdeps/pthread/unwind-resume.c b/libpthread/nptl/sysdeps/pthread/unwind-resume.c new file mode 100644 index 000000000..018d2fd2f --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/unwind-resume.c @@ -0,0 +1,72 @@ +/* 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 <stdlib.h> +#include <unwind.h> + +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 *); + +extern +void abort(void); + +static void +init (void) +{ +  void *resume = NULL; +  void *personality = NULL; +  void *handle; +  resume = personality = NULL; /* make gcc silent */ +  handle = dlopen ("libgcc_s.so.1", (RTLD_LOCAL | RTLD_LAZY)); + +  if (handle == NULL +      || (resume = dlsym (handle, "_Unwind_Resume")) == NULL +      || (personality = dlsym (handle, "__gcc_personality_v0")) == NULL) +  { +    printf("libgcc_s.so.1 must be installed for pthread_cancel to work\n"); +    abort(); +  } + +  libgcc_s_resume = resume; +  libgcc_s_personality = personality; +} + +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); +} diff --git a/libpthread/nptl/sysdeps/sh/Makefile b/libpthread/nptl/sysdeps/sh/Makefile new file mode 100644 index 000000000..81bddf688 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/Makefile @@ -0,0 +1,3 @@ +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif diff --git a/libpthread/nptl/sysdeps/sh/Makefile.arch b/libpthread/nptl/sysdeps/sh/Makefile.arch new file mode 100644 index 000000000..83db10fbe --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/Makefile.arch @@ -0,0 +1,56 @@ +# 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. +# + +libpthread_SSRC = pthread_spin_unlock.S pthread_spin_trylock.S +libpthread_CSRC = pthread_spin_lock.c pthread_spin_init.c + +ASFLAGS-pthread_spin_unlock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +ASFLAGS-pthread_spin_trylock.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +CFLAGS-pthread_spin_lock.c += -D_GNU_SOURCE + +CFLAGS-sh = $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +PTHREAD_ARCH_DIR := $(top_srcdir)libpthread/nptl/sysdeps/sh +PTHREAD_ARCH_OUT := $(top_builddir)libpthread/nptl/sysdeps/sh +PTHREAD_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_SSRC)) +PTHREAD_ARCH_OBJ += $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(PTHREAD_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(PTHREAD_ARCH_OBJ) +endif +libpthread-so-y += $(PTHREAD_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y += $(PTHREAD_ARCH_OBJ) + +objclean-y += nptl_arch_clean +headers_clean-y += nptl_arch_headers_clean + +# +# Create 'tcb-offsets.h' header file. +# +CFLAGS-tcb-offsets.c = -S + +$(PTHREAD_ARCH_OUT)/tcb-offsets.c: $(PTHREAD_ARCH_DIR)/tcb-offsets.sym +	$(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_ARCH_OUT)/tcb-offsets.s: $(PTHREAD_ARCH_OUT)/tcb-offsets.c +	$(compile.c) + +$(PTHREAD_ARCH_OUT)/tcb-offsets.h: $(PTHREAD_ARCH_OUT)/tcb-offsets.s +	$(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +nptl_arch_headers: $(PTHREAD_ARCH_OUT)/tcb-offsets.h + +nptl_arch_headers_clean: +	$(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/tcb-offsets., c s h) + +nptl_arch_clean: +	$(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/sh/dl-tls.h b/libpthread/nptl/sysdeps/sh/dl-tls.h new file mode 100644 index 000000000..98e2f1904 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/dl-tls.h @@ -0,0 +1,29 @@ +/* Thread-local storage handling in the ELF dynamic linker.  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 Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License 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.  */ + + +/* Type used for the representation of TLS information in the GOT.  */ +typedef struct +{ +  unsigned long int ti_module; +  unsigned long int ti_offset; +} tls_index; + + +extern void *__tls_get_addr (tls_index *ti); diff --git a/libpthread/nptl/sysdeps/sh/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/sh/jmpbuf-unwind.h new file mode 100644 index 000000000..41c3c3984 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/jmpbuf-unwind.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2003, 2004 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 <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ +  _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(jmpbuf, address, adj) \ +  ((uintptr_t) (address) - (adj) < (uintptr_t) (jmpbuf)[0].__regs[7] - (adj)) + +extern __typeof(longjmp) __libc_longjmp attribute_noreturn; + +/* We use the normal lobngjmp for unwinding.  */ +#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/sh/pthread_spin_init.c b/libpthread/nptl/sysdeps/sh/pthread_spin_init.c new file mode 100644 index 000000000..0a47981aa --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/pthread_spin_init.c @@ -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.  */ + +/* Not needed.  pthread_spin_init is an alias for pthread_spin_unlock.  */ diff --git a/libpthread/nptl/sysdeps/sh/pthread_spin_lock.c b/libpthread/nptl/sysdeps/sh/pthread_spin_lock.c new file mode 100644 index 000000000..d158183f0 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/pthread_spin_lock.c @@ -0,0 +1,35 @@ +/* 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 "pthreadP.h" + +int +pthread_spin_lock (lock) +     pthread_spinlock_t *lock; +{ +  unsigned int val; + +  do +    __asm__ volatile ("tas.b @%1; movt %0" +		  : "=&r" (val) +		  : "r" (lock) +		  : "memory"); +  while (val == 0); + +  return 0; +} diff --git a/libpthread/nptl/sysdeps/sh/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/sh/pthread_spin_trylock.S new file mode 100644 index 000000000..18112ba23 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/pthread_spin_trylock.S @@ -0,0 +1,32 @@ +/* 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 <pthread-errnos.h> + +	.globl	pthread_spin_trylock +	.type	pthread_spin_trylock,@function +	.align	5 +pthread_spin_trylock: +	tas.b	@r4 +	bf/s	1f +	mov	#EBUSY, r0 +	mov	#0, r0 +1: +	rts +	 nop +	.size	pthread_spin_trylock,.-pthread_spin_trylock diff --git a/libpthread/nptl/sysdeps/sh/pthread_spin_unlock.S b/libpthread/nptl/sysdeps/sh/pthread_spin_unlock.S new file mode 100644 index 000000000..c77acaffe --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/pthread_spin_unlock.S @@ -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.  */ + +	.globl	pthread_spin_unlock +	.type	pthread_spin_unlock,@function +	.align	5 +pthread_spin_unlock: +	mov	#0,r0 +	rts +	 mov.l	r0,@r4 +	.size	pthread_spin_unlock,.-pthread_spin_unlock + +	/* The implementation of pthread_spin_init is identical.  */ +	.globl	pthread_spin_init +pthread_spin_init = pthread_spin_unlock diff --git a/libpthread/nptl/sysdeps/sh/pthreaddef.h b/libpthread/nptl/sysdeps/sh/pthreaddef.h new file mode 100644 index 000000000..c1902fb54 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/pthreaddef.h @@ -0,0 +1,49 @@ +/* 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 <sysdep.h> + +/* Default stack size.  */ +#define ARCH_STACK_DEFAULT_SIZE	(2 * 1024 * 1024) + +/* Required stack pointer alignment at beginning.  */ +#define STACK_ALIGN		8 + +/* Minimal stack size after allocating thread descriptor and guard size.  */ +#define MINIMAL_REST_STACK	2048 + +/* Alignment requirement for TCB.  */ +#define TCB_ALIGNMENT		8 + + +/* Location of current stack frame.  */ +#define CURRENT_STACK_FRAME	__builtin_frame_address (0) + + +/* XXX Until we have a better place keep the definitions here.  */ + +/* While there is no such syscall.  */ +#define __exit_thread_inline(val) \ +  while (1) {								      \ +    if (__builtin_constant_p (val) && (val) == 0)			      \ +      __asm__ volatile ("mov #0,r4; mov %0,r3; trapa #0x11\n\t" SYSCALL_INST_PAD  \ +		   :: "i" (__NR_exit));  \ +    else								      \ +      __asm__ volatile ("mov %1,r4; mov %0,r3; trapa #0x11\n\t" SYSCALL_INST_PAD  \ +		    :: "i" (__NR_exit), "r" (val));			      \ +  } diff --git a/libpthread/nptl/sysdeps/sh/sysdep.h b/libpthread/nptl/sysdeps/sh/sysdep.h new file mode 100644 index 000000000..5b75198f9 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/sysdep.h @@ -0,0 +1,82 @@ +/* Assembler macros for SH. +   Copyright (C) 1999, 2000, 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 <sysdeps/generic/sysdep.h> + +#include <features.h> +#include <libc-internal.h> + +#ifdef	__ASSEMBLER__ + +/* Syntactic details of assembler.  */ + +#define ALIGNARG(log2) log2 +/* For ELF we need the `.type' directive to make shared libs work right.  */ +#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,@##typearg; +#define ASM_SIZE_DIRECTIVE(name) .size name,.-name + +#ifdef SHARED +#define PLTJMP(_x)	_x##@PLT +#else +#define PLTJMP(_x)	_x +#endif + +/* Define an entry point visible from C.  */ +#define	ENTRY(name)							      \ +  ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name);				      \ +  ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),function)			      \ +  .align ALIGNARG(5);							      \ +  C_LABEL(name)								      \ +  cfi_startproc;							      \ +  CALL_MCOUNT + +#undef	END +#define END(name)							      \ +  cfi_endproc;								      \ +  ASM_SIZE_DIRECTIVE(C_SYMBOL_NAME(name)) + +/* If compiled for profiling, call `mcount' at the start of each function.  */ +#ifdef	PROF +#define CALL_MCOUNT					\ +	mov.l	1f,r1;					\ +	sts.l	pr,@-r15;				\ +	cfi_adjust_cfa_offset (4);			\ +	cfi_rel_offset (pr, 0);				\ +	mova	2f,r0;					\ +	jmp	@r1;					\ +	 lds	r0,pr;					\ +	.align	2;					\ +1:	.long	mcount;					\ +2:	lds.l	@r15+,pr;				\ +	cfi_adjust_cfa_offset (-4);			\ +	cfi_restore (pr) + +#else +#define CALL_MCOUNT		/* Do nothing.  */ +#endif + +#ifdef	__UCLIBC_UNDERSCORES__ +/* Since C identifiers are not normally prefixed with an underscore +   on this system, the asm identifier `syscall_error' intrudes on the +   C name space.  Make sure we use an innocuous name.  */ +#define	syscall_error	__syscall_error +#define mcount		_mcount +#endif + +#endif	/* __ASSEMBLER__ */ diff --git a/libpthread/nptl/sysdeps/sh/tcb-offsets.sym b/libpthread/nptl/sysdeps/sh/tcb-offsets.sym new file mode 100644 index 000000000..539789a81 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/tcb-offsets.sym @@ -0,0 +1,11 @@ +#include <sysdep.h> +#include <tls.h> + +RESULT			offsetof (struct pthread, result) +TID			offsetof (struct pthread, tid) +PID			offsetof (struct pthread, pid) +CANCELHANDLING		offsetof (struct pthread, cancelhandling) +CLEANUP_JMP_BUF		offsetof (struct pthread, cleanup_jmp_buf) +MULTIPLE_THREADS_OFFSET	offsetof (struct pthread, header.multiple_threads) +TLS_PRE_TCB_SIZE	sizeof (struct pthread) +MUTEX_FUTEX		offsetof (pthread_mutex_t, __data.__lock) diff --git a/libpthread/nptl/sysdeps/sh/tls.h b/libpthread/nptl/sysdeps/sh/tls.h new file mode 100644 index 000000000..5e5ce12b0 --- /dev/null +++ b/libpthread/nptl/sysdeps/sh/tls.h @@ -0,0 +1,142 @@ +/* Definition for thread-local data handling.  NPTL/SH version. +   Copyright (C) 2003, 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.  */ + +#ifndef _TLS_H +#define _TLS_H + +#ifndef __ASSEMBLER__ +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> + +/* Type for the dtv.  */ +typedef union dtv +{ +  size_t counter; +  struct +  { +    void *val; +    bool is_static; +  } pointer; +} dtv_t; + +typedef struct +{ +  dtv_t *dtv; +  void *private; +} tcbhead_t; + +# define TLS_MULTIPLE_THREADS_IN_TCB 1 + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif /* __ASSEMBLER__ */ + + +/* We require TLS support in the tools.  */ +#define HAVE_TLS_SUPPORT +#define HAVE___THREAD   1 +#define HAVE_TLS_MODEL_ATTRIBUTE	1 +/* Signal that TLS support is available.  */ +# define USE_TLS	1 + +#ifndef __ASSEMBLER__ + +/* Get system call information.  */ +# include <sysdep.h> + +/* This is the size of the initial TCB.  */ +# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t) + +/* Alignment requirements for the initial TCB.  */ +# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t) + +/* This is the size of the TCB.  */ +# define TLS_TCB_SIZE sizeof (tcbhead_t) + +/* This is the size we need before TCB.  */ +# define TLS_PRE_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the TCB.  */ +# define TLS_TCB_ALIGN __alignof__ (struct pthread) + +/* The TLS blocks start right after the TCB.  */ +# define TLS_DTV_AT_TP	1 + +/* Get the thread descriptor definition.  */ +# include <descr.h> + +/* Install the dtv pointer.  The pointer passed is to the element with +   index -1 which contain the length.  */ +# define INSTALL_DTV(tcbp, dtvp) \ +  ((tcbhead_t *) (tcbp))->dtv = (dtvp) + 1 + +/* Install new dtv for current thread.  */ +# define INSTALL_NEW_DTV(dtv) \ +  ({ tcbhead_t *__tcbp;							      \ +     __asm __volatile ("stc gbr,%0" : "=r" (__tcbp));			      \ +     __tcbp->dtv = (dtv);}) + +/* Return dtv of given thread descriptor.  */ +# define GET_DTV(tcbp) \ +  (((tcbhead_t *) (tcbp))->dtv) + +/* Code to initially initialize the thread pointer.  This might need +   special attention since 'errno' is not yet available and if the +   operation can cause a failure 'errno' must not be touched.  */ +# define TLS_INIT_TP(tcbp, secondcall) \ +  ({ __asm __volatile ("ldc %0,gbr" : : "r" (tcbp)); 0; }) + +/* Return the address of the dtv for the current thread.  */ +# define THREAD_DTV() \ +  ({ tcbhead_t *__tcbp;							      \ +     __asm __volatile ("stc gbr,%0" : "=r" (__tcbp));			      \ +     __tcbp->dtv;}) + +/* Return the thread descriptor for the current thread. +   The contained asm must *not* be marked volatile since otherwise +   assignments like +        struct pthread *self = thread_self(); +   do not get optimized away.  */ +# define THREAD_SELF \ +  ({ struct pthread *__thread_self;						      \ +     __asm ("stc gbr,%0" : "=r" (__thread_self));				      \ +     __thread_self - 1;}) + +/* Magic for libthread_db to know how to do THREAD_SELF.  */ +# define DB_THREAD_SELF \ +  REGISTER (32, 32, REG_GBR * 4, -sizeof (struct pthread)) + +/* Read member of the thread descriptor directly.  */ +# define THREAD_GETMEM(descr, member) (descr->member) + +/* Same as THREAD_GETMEM, but the member offset can be non-constant.  */ +# define THREAD_GETMEM_NC(descr, member, idx) (descr->member[idx]) + +/* Set member of the thread descriptor directly.  */ +# define THREAD_SETMEM(descr, member, value) \ +    descr->member = (value) + +/* Same as THREAD_SETMEM, but the member offset can be non-constant.  */ +# define THREAD_SETMEM_NC(descr, member, idx, value) \ +    descr->member[idx] = (value) + +#endif /* __ASSEMBLER__ */ + +#endif	/* tls.h */ diff --git a/libpthread/nptl/sysdeps/sparc/Makefile b/libpthread/nptl/sysdeps/sparc/Makefile new file mode 100644 index 000000000..81bddf688 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/Makefile @@ -0,0 +1,3 @@ +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif diff --git a/libpthread/nptl/sysdeps/sparc/Makefile.arch b/libpthread/nptl/sysdeps/sparc/Makefile.arch new file mode 100644 index 000000000..b13eee9f6 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/Makefile.arch @@ -0,0 +1,53 @@ +# 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. +# + +libpthread_CSRC = sparc32/pthread_spin_lock.c \ +				  sparc32/pthread_spin_trylock.c + +CFLAGS-pthread_spin_lock.c += -D_GNU_SOURCE + +CFLAGS-sparc = $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +PTHREAD_ARCH_DIR := $(top_srcdir)libpthread/nptl/sysdeps/sparc/ +PTHREAD_ARCH_OUT := $(top_builddir)libpthread/nptl/sysdeps/sparc/ +PTHREAD_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_SSRC)) +PTHREAD_ARCH_OBJ += $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(PTHREAD_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(PTHREAD_ARCH_OBJ) +endif +libpthread-so-y += $(PTHREAD_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y += $(PTHREAD_ARCH_OBJ) + +objclean-y += nptl_arch_clean +headers_clean-y += nptl_arch_headers_clean + +# +# Create 'tcb-offsets.h' header file. +# +CFLAGS-tcb-offsets.c = -S + +$(PTHREAD_ARCH_OUT)/tcb-offsets.c: $(PTHREAD_ARCH_DIR)/tcb-offsets.sym +	$(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_ARCH_OUT)/tcb-offsets.s: $(PTHREAD_ARCH_OUT)/tcb-offsets.c +	$(compile.c) + +$(PTHREAD_ARCH_OUT)/tcb-offsets.h: $(PTHREAD_ARCH_OUT)/tcb-offsets.s +	@sed -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +nptl_arch_headers: $(PTHREAD_ARCH_OUT)/tcb-offsets.h + +nptl_arch_headers_clean: +	$(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/tcb-offsets., c s h) + +nptl_arch_clean: +	$(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/sparc/dl-tls.h b/libpthread/nptl/sysdeps/sparc/dl-tls.h new file mode 100644 index 000000000..6edf8d525 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/dl-tls.h @@ -0,0 +1,29 @@ +/* Thread-local storage handling in the ELF dynamic linker.  SPARC 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.  */ + + +/* Type used for the representation of TLS information in the GOT.  */ +typedef struct +{ +  unsigned long int ti_module; +  unsigned long int ti_offset; +} tls_index; + + +extern void *__tls_get_addr (tls_index *ti); diff --git a/libpthread/nptl/sysdeps/sparc/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/sparc/jmpbuf-unwind.h new file mode 100644 index 000000000..6cbb37baf --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/jmpbuf-unwind.h @@ -0,0 +1,5 @@ +#if defined(__arch64__) +#include "sparc64/jmpbuf-unwind.h" +#else +#include "sparc32/jmpbuf-unwind.h" +#endif diff --git a/libpthread/nptl/sysdeps/sparc/pthreaddef.h b/libpthread/nptl/sysdeps/sparc/pthreaddef.h new file mode 100644 index 000000000..d4695c47d --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/pthreaddef.h @@ -0,0 +1,5 @@ +#if defined(__arch64__) +#include "sparc64/pthreaddef.h" +#else +#include "sparc32/pthreaddef.h" +#endif diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/sparc/sparc32/jmpbuf-unwind.h new file mode 100644 index 000000000..71a358209 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc32/jmpbuf-unwind.h @@ -0,0 +1,32 @@ +/* Copyright (C) 2003, 2004 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 <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ +  _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ +  ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_SP] - (_adj)) + +/* We use the normal longjmp for unwinding.  */ +extern __typeof(longjmp) __libc_longjmp attribute_noreturn; +#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/pthread_spin_lock.c b/libpthread/nptl/sysdeps/sparc/sparc32/pthread_spin_lock.c new file mode 100644 index 000000000..d3c6e3049 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc32/pthread_spin_lock.c @@ -0,0 +1,40 @@ +/* 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 "pthreadP.h" + +int +pthread_spin_lock (pthread_spinlock_t *lock) +{ +  __asm __volatile +    ("1: ldstub [%0], %%g2\n" +     "   orcc   %%g2, 0x0, %%g0\n" +     "   bne,a  2f\n" +     "   ldub   [%0], %%g2\n" +     ".subsection 2\n" +     "2: orcc   %%g2, 0x0, %%g0\n" +     "   bne,a  2b\n" +     "   ldub   [%0], %%g2\n" +     "   b,a    1b\n" +     ".previous" +     : /* no outputs */ +     : "r" (lock) +     : "g2", "memory", "cc"); +  return 0; +} diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/pthread_spin_trylock.c b/libpthread/nptl/sysdeps/sparc/sparc32/pthread_spin_trylock.c new file mode 100644 index 000000000..bcc3158fd --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc32/pthread_spin_trylock.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 <errno.h> +#include "pthreadP.h" + +int +pthread_spin_trylock (pthread_spinlock_t *lock) +{ +  int res; +  __asm __volatile ("ldstub [%1], %0" : "=r" (res) : "r" (lock) : "memory"); +  return res == 0 ? 0 : EBUSY; +} diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/pthreaddef.h b/libpthread/nptl/sysdeps/sparc/sparc32/pthreaddef.h new file mode 100644 index 000000000..9908df9e9 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc32/pthreaddef.h @@ -0,0 +1,40 @@ +/* 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.  */ + +/* Default stack size.  */ +#define ARCH_STACK_DEFAULT_SIZE	(2 * 1024 * 1024) + +/* Required stack pointer alignment at beginning.  */ +#define STACK_ALIGN		16 + +/* Minimal stack size after allocating thread descriptor and guard size.  */ +#define MINIMAL_REST_STACK	2048 + +/* Alignment requirement for TCB.  */ +#define TCB_ALIGNMENT		16 + + +/* Location of current stack frame.  */ +#define CURRENT_STACK_FRAME  (stack_pointer + (2 * 64)) +register char *stack_pointer __asm__("%sp"); + +/* XXX Until we have a better place keep the definitions here.  */ + +/* While there is no such syscall.  */ +#define __exit_thread_inline(val) \ +  INLINE_SYSCALL (exit, 1, (val)) diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_lock.c b/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_lock.c new file mode 100644 index 000000000..8880f535b --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_lock.c @@ -0,0 +1,39 @@ +/* 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 "pthreadP.h" + +int +pthread_spin_lock (pthread_spinlock_t *lock) +{ +  __asm __volatile +    ("1: ldstub  [%0], %%g2\n" +     "   brnz,pn %%g2, 2f\n" +     "    membar #StoreLoad | #StoreStore\n" +     ".subsection 2\n" +     "2: ldub    [%0], %%g2\n" +     "   brnz,pt %%g2, 2b\n" +     "    membar #LoadLoad\n" +     "   b,a,pt  %%xcc, 1b\n" +     ".previous" +     : /* no outputs */ +     : "r" (lock) +     : "g2", "memory"); +  return 0; +} diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_trylock.c b/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_trylock.c new file mode 100644 index 000000000..3b20a2180 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_trylock.c @@ -0,0 +1 @@ +#include <sparc64/pthread_spin_trylock.c> diff --git a/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_unlock.c b/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_unlock.c new file mode 100644 index 000000000..482cbe3d7 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc32/sparcv9/pthread_spin_unlock.c @@ -0,0 +1 @@ +#include <sparc64/pthread_spin_unlock.c> diff --git a/libpthread/nptl/sysdeps/sparc/sparc64/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/sparc/sparc64/jmpbuf-unwind.h new file mode 100644 index 000000000..5cef8b1cf --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc64/jmpbuf-unwind.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2003, 2004 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 <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ +  _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ +  ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_SP] - (_adj)) + +/* We use the normal lobngjmp for unwinding.  */ +#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_lock.c b/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_lock.c new file mode 100644 index 000000000..77171d9b9 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_lock.c @@ -0,0 +1,39 @@ +/* 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 "pthreadP.h" + +int +pthread_spin_lock (pthread_spinlock_t *lock) +{ +  __asm __volatile +    ("1: ldstub  [%0], %%g5\n" +     "   brnz,pn %%g5, 2f\n" +     "    membar #StoreLoad | #StoreStore\n" +     ".subsection 2\n" +     "2: ldub    [%0], %%g5\n" +     "   brnz,pt %%g5, 2b\n" +     "    membar #LoadLoad\n" +     "   b,a,pt  %%xcc, 1b\n" +     ".previous" +     : /* no outputs */ +     : "r" (lock) +     : "g5", "memory"); +  return 0; +} diff --git a/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_trylock.c b/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_trylock.c new file mode 100644 index 000000000..2bda809da --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_trylock.c @@ -0,0 +1,34 @@ +/* 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 <errno.h> +#include "pthreadP.h" + +int +pthread_spin_trylock (pthread_spinlock_t *lock) +{ +  int res; +  __asm __volatile +    ("ldstub [%1], %0\n" +     "membar #StoreLoad | #StoreStore" +     : "=r" (res) +     : "r" (lock) +     : "memory"); +  return res == 0 ? 0 : EBUSY; +} diff --git a/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_unlock.c b/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_unlock.c new file mode 100644 index 000000000..7037675a2 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc64/pthread_spin_unlock.c @@ -0,0 +1,30 @@ +/* pthread_spin_unlock -- unlock a spin lock.  Generic 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 "pthreadP.h" +#include <atomic.h> + +int +pthread_spin_unlock (pthread_spinlock_t *lock) +{ +  __asm __volatile ("membar #StoreStore | #LoadStore"); +  *lock = 0; +  return 0; +} diff --git a/libpthread/nptl/sysdeps/sparc/sparc64/pthreaddef.h b/libpthread/nptl/sysdeps/sparc/sparc64/pthreaddef.h new file mode 100644 index 000000000..ec7651211 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/sparc64/pthreaddef.h @@ -0,0 +1,40 @@ +/* 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.  */ + +/* Default stack size.  */ +#define ARCH_STACK_DEFAULT_SIZE	(4 * 1024 * 1024) + +/* Required stack pointer alignment at beginning.  */ +#define STACK_ALIGN		16 + +/* Minimal stack size after allocating thread descriptor and guard size.  */ +#define MINIMAL_REST_STACK	4096 + +/* Alignment requirement for TCB.  */ +#define TCB_ALIGNMENT		16 + + +/* Location of current stack frame.  */ +#define CURRENT_STACK_FRAME  (stack_pointer + (2 * 128)) +register char *stack_pointer __asm__("%sp"); + +/* XXX Until we have a better place keep the definitions here.  */ + +/* While there is no such syscall.  */ +#define __exit_thread_inline(val) \ +  INLINE_SYSCALL (exit, 1, (val)) diff --git a/libpthread/nptl/sysdeps/sparc/tcb-offsets.sym b/libpthread/nptl/sysdeps/sparc/tcb-offsets.sym new file mode 100644 index 000000000..237f975b2 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/tcb-offsets.sym @@ -0,0 +1,6 @@ +#include <sysdep.h> +#include <tls.h> + +MULTIPLE_THREADS_OFFSET		offsetof (tcbhead_t, multiple_threads) +PID				offsetof (struct pthread, pid) +TID				offsetof (struct pthread, tid) diff --git a/libpthread/nptl/sysdeps/sparc/tls.h b/libpthread/nptl/sysdeps/sparc/tls.h new file mode 100644 index 000000000..e5d27fb57 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/tls.h @@ -0,0 +1,139 @@ +/* Definitions for thread-local data handling.  NPTL/sparc version. +   Copyright (C) 2003, 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.  */ + +#ifndef _TLS_H +#define _TLS_H + +#ifndef __ASSEMBLER__ +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> +# include <stdlib.h> +# include <list.h> + +/* Type for the dtv.  */ +typedef union dtv +{ +  size_t counter; +  struct +  { +    void *val; +    bool is_static; +  } pointer; +} dtv_t; + +typedef struct +{ +  void *tcb;		/* Pointer to the TCB.  Not necessary the +			   thread descriptor used by libpthread.  */ +  dtv_t *dtv; +  void *self; +  int multiple_threads; +  uintptr_t sysinfo; +  uintptr_t stack_guard; +} tcbhead_t; + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif /* __ASSEMBLER__ */ + +/* We require TLS support in the tools.  */ +#define HAVE_TLS_SUPPORT +#define HAVE___THREAD 1 +#define HAVE_TLS_MODEL_ATTRIBUTE 1 + +/* Signal that TLS support is available.  */ +#define USE_TLS	1 + +#ifndef __ASSEMBLER__ +/* Get system call information.  */ +# include <sysdep.h> + +register struct pthread *__thread_self __asm__("%g7"); + +/* This is the size of the initial TCB.  Can't be just sizeof (tcbhead_t), +   because NPTL getpid, __libc_alloca_cutoff etc. need (almost) the whole +   struct pthread even when not linked with -lpthread.  */ +# define TLS_INIT_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the initial TCB.  */ +# define TLS_INIT_TCB_ALIGN __alignof__ (struct pthread) + +/* This is the size of the TCB.  */ +# define TLS_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the TCB.  */ +# define TLS_TCB_ALIGN __alignof__ (struct pthread) + +/* Get the thread descriptor definition.  */ +# include <descr.h> + +/* The TCB can have any size and the memory following the address the +   thread pointer points to is unspecified.  Allocate the TCB there.  */ +# define TLS_TCB_AT_TP	1 + +/* Install the dtv pointer.  The pointer passed is to the element with +   index -1 which contain the length.  */ +# define INSTALL_DTV(descr, dtvp) \ +  ((tcbhead_t *) (descr))->dtv = (dtvp) + 1 + +/* Install new dtv for current thread.  */ +# define INSTALL_NEW_DTV(DTV) \ +  (((tcbhead_t *) __thread_self)->dtv = (DTV)) + +/* Return dtv of given thread descriptor.  */ +# define GET_DTV(descr) \ +  (((tcbhead_t *) (descr))->dtv) + +/* Code to initially initialize the thread pointer.  */ +# define TLS_INIT_TP(descr, secondcall) \ +  (__thread_self = (__typeof (__thread_self)) (descr), NULL) + +/* Return the address of the dtv for the current thread.  */ +# define THREAD_DTV() \ +  (((tcbhead_t *) __thread_self)->dtv) + +/* Return the thread descriptor for the current thread.  */ +#define THREAD_SELF  __thread_self + +/* Magic for libthread_db to know how to do THREAD_SELF.  */ +# define DB_THREAD_SELF_INCLUDE <sys/ucontext.h> +# define DB_THREAD_SELF \ +  REGISTER (32, 32, REG_G7 * 4, 0) REGISTER (64, 64, REG_G7 * 8, 0) + +/* Access to data in the thread descriptor is easy.  */ +#define THREAD_GETMEM(descr, member) \ +  descr->member +#define THREAD_GETMEM_NC(descr, member, idx) \ +  descr->member[idx] +#define THREAD_SETMEM(descr, member, value) \ +  descr->member = (value) +#define THREAD_SETMEM_NC(descr, member, idx, value) \ +  descr->member[idx] = (value) + +/* Set the stack guard field in TCB head.  */ +#define THREAD_SET_STACK_GUARD(value) \ +  THREAD_SETMEM (THREAD_SELF, header.stack_guard, value) +# define THREAD_COPY_STACK_GUARD(descr) \ +  ((descr)->header.stack_guard \ +   = THREAD_GETMEM (THREAD_SELF, header.stack_guard)) + +#endif /* !ASSEMBLER */ + +#endif	/* tls.h */ diff --git a/libpthread/nptl/sysdeps/unix/sh/sysdep.h b/libpthread/nptl/sysdeps/unix/sh/sysdep.h new file mode 100644 index 000000000..bf1ac0fd4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sh/sysdep.h @@ -0,0 +1,29 @@ +/* Copyright (C) 1999, 2000 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 <sysdeps/unix/sysdep.h> +#include <sysdeps/sh/sysdep.h> + +#ifdef __ASSEMBLER__ + +#define ret	rts ; nop + +/* The sh move insn is s, d.  */ +#define MOVE(x,y)	mov x , y + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysdep.h b/libpthread/nptl/sysdeps/unix/sysdep.h new file mode 100644 index 000000000..0e7c9da5a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysdep.h @@ -0,0 +1,63 @@ +/* Copyright (C) 1991, 92, 93, 96, 98, 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 <sysdeps/generic/sysdep.h> + +#include <sys/syscall.h> +#define	HAVE_SYSCALLS + +/* Note that using a `PASTE' macro loses.  */ +#ifdef	__STDC__ +#define	SYSCALL__(name, args)	PSEUDO (__##name, name, args) +#else +#define	SYSCALL__(name, args)	PSEUDO (__/**/name, name, args) +#endif +#define	SYSCALL(name, args)	PSEUDO (name, name, args) + +/* Machine-dependent sysdep.h files are expected to define the macro +   PSEUDO (function_name, syscall_name) to emit assembly code to define the +   C-callable function FUNCTION_NAME to do system call SYSCALL_NAME. +   r0 and r1 are the system call outputs.  MOVE(x, y) should be defined as +   an instruction such that "MOVE(r1, r0)" works.  ret should be defined +   as the return instruction.  */ + +#ifndef SYS_ify +#ifdef __STDC__ +#define SYS_ify(syscall_name) SYS_##syscall_name +#else +#define SYS_ify(syscall_name) SYS_/**/syscall_name +#endif +#endif + +/* Terminate a system call named SYM.  This is used on some platforms +   to generate correct debugging information.  */ +#ifndef PSEUDO_END +#define PSEUDO_END(sym) +#endif +#ifndef PSEUDO_END_NOERRNO +#define PSEUDO_END_NOERRNO(sym)	PSEUDO_END(sym) +#endif +#ifndef PSEUDO_END_ERRVAL +#define PSEUDO_END_ERRVAL(sym)	PSEUDO_END(sym) +#endif + +/* Wrappers around system calls should normally inline the system call code. +   But sometimes it is not possible or implemented and we use this code.  */ +#ifndef INLINE_SYSCALL +#define INLINE_SYSCALL(name, nr, args...) __syscall_##name (args) +#endif diff --git a/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..6c491b6e5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile.in @@ -0,0 +1,208 @@ +# 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		\ +		  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)) +endif + +ifeq ($(TARGET_ARCH),mips) +libpthread_CSRC += lowlevellock.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 +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)) +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 + +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-lowlevelbarrier.c = -S +CFLAGS-lowlevelcond.c = -S +CFLAGS-lowlevelrwlock.c = -S +CFLAGS-unwindbuf.c = -S + +$(PTHREAD_LINUX_OUT)/lowlevelbarrier.c: $(PTHREAD_LINUX_DIR)/lowlevelbarrier.sym +	$(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_LINUX_OUT)/lowlevelcond.c: $(PTHREAD_LINUX_DIR)/lowlevelcond.sym +	$(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_LINUX_OUT)/lowlevelrwlock.c: $(PTHREAD_LINUX_DIR)/lowlevelrwlock.sym +	$(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_LINUX_OUT)/unwindbuf.c: $(PTHREAD_LINUX_DIR)/unwindbuf.sym +	$(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_LINUX_OUT)/lowlevelbarrier.s: $(PTHREAD_LINUX_OUT)/lowlevelbarrier.c +	$(compile.c) + +$(PTHREAD_LINUX_OUT)/lowlevelcond.s: $(PTHREAD_LINUX_OUT)/lowlevelcond.c +	$(compile.c) + +$(PTHREAD_LINUX_OUT)/lowlevelrwlock.s: $(PTHREAD_LINUX_OUT)/lowlevelrwlock.c +	$(compile.c) + +$(PTHREAD_LINUX_OUT)/unwindbuf.s: $(PTHREAD_LINUX_OUT)/unwindbuf.c +	$(compile.c) + +$(PTHREAD_LINUX_OUT)/lowlevelbarrier.h: $(PTHREAD_LINUX_OUT)/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)/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)/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)/unwindbuf.h: $(PTHREAD_LINUX_OUT)/unwindbuf.s +	$(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +nptl_linux_headers: $(PTHREAD_LINUX_OUT)/lowlevelbarrier.h \ +					$(PTHREAD_LINUX_OUT)/lowlevelcond.h \ +					$(PTHREAD_LINUX_OUT)/lowlevelrwlock.h \ +					$(PTHREAD_LINUX_OUT)/unwindbuf.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)/lowlevelbarrier., c h s) \ +	$(addprefix $(PTHREAD_LINUX_OUT)/lowlevelcond., c h s) \ +	$(addprefix $(PTHREAD_LINUX_OUT)/lowlevelrwlock., c h s) \ +	$(addprefix $(PTHREAD_LINUX_OUT)/unwindbuf., c h s) + + +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/Versions b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/Versions new file mode 100644 index 000000000..437c4da28 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/Versions @@ -0,0 +1,13 @@ +libpthread { +  GLIBC_2.3.3 { +    # Changed PTHREAD_STACK_MIN. +    pthread_attr_setstack; pthread_attr_setstacksize; +  } +} +librt { +  GLIBC_2.3.3 { +    # Changed timer_t. +    timer_create; timer_delete; timer_getoverrun; timer_gettime; +    timer_settime; +  } +} 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..e0718780c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/local_lim.h @@ -0,0 +1,89 @@ +/* Minimum guaranteed maximum values for system limits.  Linux/Alpha version. +   Copyright (C) 1993-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 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 + +/* 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 + +/* 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 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..0f3bf838e --- /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 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 __pad1; +    unsigned long int __pad2; +    unsigned long int __pad3; +    /* 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..6dadfda20 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/bits/semaphore.h @@ -0,0 +1,37 @@ +/* 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) + +/* Maximum value the semaphore can have.  */ +#define SEM_VALUE_MAX   (2147483647) + + +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..fd4a7ca4b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/lowlevellock.h @@ -0,0 +1,217 @@ +/* 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 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> + + +#define __NR_futex		394 +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 +#define FUTEX_REQUEUE		3 +#define FUTEX_CMP_REQUEUE	4 + +/* Initializer for compatibility lock.	*/ +#define LLL_MUTEX_LOCK_INITIALIZER (0) + +#define lll_futex_wait(futexp, val) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4,				      \ +			      (futexp), FUTEX_WAIT, (val), 0);		      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err)? -__ret : __ret;		      \ +  }) + +#define lll_futex_timed_wait(futexp, val, timespec) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4,				      \ +			      (futexp), FUTEX_WAIT, (val), (timespec));	      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err)? -__ret : __ret;		      \ +  }) + +#define lll_futex_wake(futexp, nr) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4,				      \ +			      (futexp), FUTEX_WAKE, (nr), 0);		      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err)? -__ret : __ret;		      \ +  }) + +/* Returns non-zero if error happened, zero if success.  */ +#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 6,				      \ +			      (futexp), FUTEX_CMP_REQUEUE, (nr_wake),	      \ +			      (nr_move), (mutex), (val));		      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err);				      \ +  }) + + +static inline int __attribute__((always_inline)) +__lll_mutex_trylock(int *futex) +{ +  return atomic_compare_and_exchange_val_acq (futex, 1, 0) != 0; +} +#define lll_mutex_trylock(lock)	__lll_mutex_trylock (&(lock)) + + +static inline int __attribute__((always_inline)) +__lll_mutex_cond_trylock(int *futex) +{ +  return atomic_compare_and_exchange_val_acq (futex, 2, 0) != 0; +} +#define lll_mutex_cond_trylock(lock)	__lll_mutex_cond_trylock (&(lock)) + + +extern void __lll_lock_wait (int *futex) attribute_hidden; + +static inline void __attribute__((always_inline)) +__lll_mutex_lock(int *futex) +{ +  if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0) +    __lll_lock_wait (futex); +} +#define lll_mutex_lock(futex) __lll_mutex_lock (&(futex)) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_cond_lock (int *futex) +{ +  if (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0) +    __lll_lock_wait (futex); +} +#define lll_mutex_cond_lock(futex) __lll_mutex_cond_lock (&(futex)) + + +extern int __lll_timedlock_wait (int *futex, const struct timespec *) +	attribute_hidden; + +static inline int __attribute__ ((always_inline)) +__lll_mutex_timedlock (int *futex, const struct timespec *abstime) +{ +  int result = 0; +  if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0) +    result = __lll_timedlock_wait (futex, abstime); +  return result; +} +#define lll_mutex_timedlock(futex, abstime) \ +  __lll_mutex_timedlock (&(futex), abstime) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_unlock (int *futex) +{ +  int val = atomic_exchange_rel (futex, 0); +  if (__builtin_expect (val > 1, 0)) +    lll_futex_wake (futex, 1); +} +#define lll_mutex_unlock(futex) __lll_mutex_unlock(&(futex)) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_unlock_force (int *futex) +{ +  (void) atomic_exchange_rel (futex, 0); +  lll_futex_wake (futex, 1); +} +#define lll_mutex_unlock_force(futex) __lll_mutex_unlock_force(&(futex)) + + +#define lll_mutex_islocked(futex) \ +  (futex != 0) + + +/* Our internal lock implementation is identical to the binary-compatible +   mutex implementation. */ + +/* Type for lock object.  */ +typedef int lll_lock_t; + +/* Initializers for lock.  */ +#define LLL_LOCK_INITIALIZER		(0) +#define LLL_LOCK_INITIALIZER_LOCKED	(1) + +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + +/* The states of a lock are: +    0  -  untaken +    1  -  taken by one user +   >1  -  taken by more users */ + +#define lll_trylock(lock)	lll_mutex_trylock (lock) +#define lll_lock(lock)		lll_mutex_lock (lock) +#define lll_unlock(lock)	lll_mutex_unlock (lock) +#define lll_islocked(lock)	lll_mutex_islocked (lock) + +/* 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);	\ +  } 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;						\ +  }) + + +/* Conditional variable handling.  */ + +extern void __lll_cond_wait (pthread_cond_t *cond) +     attribute_hidden; +extern int __lll_cond_timedwait (pthread_cond_t *cond, +				 const struct timespec *abstime) +     attribute_hidden; +extern void __lll_cond_wake (pthread_cond_t *cond) +     attribute_hidden; +extern void __lll_cond_broadcast (pthread_cond_t *cond) +     attribute_hidden; + +#define lll_cond_wait(cond) \ +  __lll_cond_wait (cond) +#define lll_cond_timedwait(cond, abstime) \ +  __lll_cond_timedwait (cond, abstime) +#define lll_cond_wake(cond) \ +  __lll_cond_wake (cond) +#define lll_cond_broadcast(cond) \ +  __lll_cond_broadcast (cond) + +#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..79a3c47ae --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/pthread_once.c @@ -0,0 +1,96 @@ +/* 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 "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); +} + +int +__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); +    } + +  /* 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); + +  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..49224079e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/alpha/sysdep-cancel.h @@ -0,0 +1,169 @@ +/* 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 <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;						\ +__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;					\ +	.previous + +# undef PSEUDO_END +# define PSEUDO_END(sym)					\ +	.subsection 2;						\ +	cfi_endproc;						\ +	.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 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..f0c39982c --- /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) +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..a82f8c8be --- /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 +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..49a935a52 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h @@ -0,0 +1,136 @@ +/* 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 __thumb__ + +/* Note that to allow efficient implementation the arguemtns are reversed +   relative to atomic_exchange_acq.  */ +int __thumb_swpb (int newvalue, void *mem) +  attribute_hidden; +unsigned int __thumb_swp (unsigned int newvalue, void *mem) +  attribute_hidden; +unsigned int __thumb_cmpxchg (unsigned int oldval, unsigned int newval, void *mem) +  attribute_hidden; + +#define atomic_exchange_acq(mem, newvalue)				      \ +  ({ __typeof (*mem) result;						      \ +     if (sizeof (*mem) == 1)						      \ +       result = __thumb_swpb (newvalue, mem);				      \ +     else if (sizeof (*mem) == 4)					      \ +       result = __thumb_swp (newvalue, mem);				      \ +     else								      \ +       {								      \ +	 result = 0;							      \ +	 abort ();							      \ +       }								      \ +     result; }) + +#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; }) + +#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \ +  ((__typeof (oldval)) __thumb_cmpxchg (oldval, newval, mem)) + +#define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \ +  ({ __arm_link_error (); oldval; }) + +#else +/* ARM mode.  */ + +#define atomic_exchange_acq(mem, newvalue)				      \ +  ({ __typeof (*mem) _xchg_result;					      \ +     if (sizeof (*mem) == 1)						      \ +       __asm__ __volatile__ ("swpb %0, %1, [%2]"			      \ +			     : "=&r,&r" (_xchg_result)			      \ +			     : "r,0" (newvalue), "r,r" (mem) : "memory");     \ +     else if (sizeof (*mem) == 4)					      \ +       __asm__ __volatile__ ("swp %0, %1, [%2]"				      \ +			     : "=&r,&r" (_xchg_result)			      \ +			     : "r,0" (newvalue), "r,r" (mem) : "memory");     \ +     else								      \ +       {								      \ +	 _xchg_result = 0;						      \ +	 abort ();							      \ +       }								      \ +     _xchg_result; }) + +/* 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.  */ + +#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%1,[%3]\n\t"					      \ +	      "cmp\t%1, %4\n\t"						      \ +	      "bne\t1f\n\t"						      \ +	      "mov\t%0, %4\n\t"						      \ +	      "mov\t%1, #0xffff0fff\n\t"				      \ +	      "mov\tlr, pc\n\t"						      \ +	      "add\tpc, %1, #(0xffff0fc0 - 0xffff0fff)\n\t"		      \ +	      "bcc\t0b\n\t"						      \ +	      "mov\t%1, %4\n\t"						      \ +	      "1:"							      \ +	      : "=&r" (a_oldval), "=&r" (a_tmp)				      \ +	      : "r" (a_newval), "r" (a_ptr), "r" (a_oldval2)		      \ +	      : "ip", "lr", "cc", "memory");				      \ +     a_tmp; }) + +#define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \ +  ({ __arm_link_error (); oldval; }) + +#endif /* __thumb__ */ 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..ea8d6a2f0 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/pthreadtypes.h @@ -0,0 +1,167 @@ +/* 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 + +#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 int __flags; +    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..3fc647d31 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/semaphore.h @@ -0,0 +1,38 @@ +/* Copyright (C) 2002, 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.  */ + +#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) + +/* Maximum value the semaphore can have.  */ +#define SEM_VALUE_MAX   ((int) ((~0u) >> 1)) + + +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..74be18855 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.c @@ -0,0 +1,118 @@ +/* low level locking for pthread library.  Generic futex-using version. +   Copyright (C) 2003, 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 <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <sys/time.h> + +int +__lll_timedlock_wait (int *futex, const struct timespec *abstime) +{ +  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; + +      lll_futex_timed_wait (futex, 2, &rt); +    } +  while (atomic_exchange_acq (futex, 2) != 0); + +  return 0; +} + + +/* These don't get included in libc.so  */ +#ifdef IS_IN_libpthread +int +lll_unlock_wake_cb (int *futex) +{ +  int val = atomic_exchange_rel (futex, 0); + +  if (__builtin_expect (val > 1, 0)) +    lll_futex_wake (futex, 1); + +  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.  */ +      if (lll_futex_timed_wait (tidp, tid, &rt) == -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..79f3ddeca --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.h @@ -0,0 +1,339 @@ +/* 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 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> + +#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) + +/* Initializer for compatibility lock.	*/ +#define LLL_MUTEX_LOCK_INITIALIZER (0) + +#define lll_futex_wait(futexp, val) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4,				      \ +			      (futexp), FUTEX_WAIT, (val), 0);		      \ +    __ret;								      \ +  }) + +#define lll_futex_timed_wait(futexp, val, timespec) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4,				      \ +			      (futexp), FUTEX_WAIT, (val), (timespec));	      \ +    __ret;								      \ +  }) + +#define lll_futex_wake(futexp, nr) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4,				      \ +			      (futexp), FUTEX_WAKE, (nr), 0);		      \ +    __ret;								      \ +  }) + +#define lll_robust_mutex_dead(futexv) \ +  do									      \ +    {									      \ +      int *__futexp = &(futexv);					      \ +      atomic_or (__futexp, FUTEX_OWNER_DIED);				      \ +      lll_futex_wake (__futexp, 1);					      \ +    }									      \ +  while (0) + +/* Returns non-zero if error happened, zero if success.  */ +#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 6,				      \ +			      (futexp), FUTEX_CMP_REQUEUE, (nr_wake),	      \ +			      (nr_move), (mutex), (val));		      \ +    __ret;								      \ +  }) + + +/* Returns non-zero if error happened, zero if success.  */ +#define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 6,				      \ +			      (futexp), FUTEX_WAKE_OP, (nr_wake),	      \ +			      (nr_wake2), (futexp2),			      \ +			      FUTEX_OP_CLEAR_WAKE_IF_GT_ONE);		      \ +    __ret;								      \ +  }) + + +static inline int __attribute__((always_inline)) +__lll_mutex_trylock (int *futex) +{ +  int flag = 1, old; +#ifdef __thumb__ +  old = atomic_exchange_acq (futex, flag); +  if (old < 1) +    flag = 0; +  else if (old > 1) +    flag = atomic_exchange_acq (futex, old); +#else +  __asm__ __volatile__ ( +    "\tswp	%[old], %[flag], [%[futex]]	@ try to take the lock\n" +    "\tcmp	%[old], #1			@ check old lock value\n" +    "\tmovlo	%[flag], #0			@ if we got it, return 0\n" +    "\tswphi	%[flag], %[old], [%[futex]]	@ if it was contested,\n" +    "						@ restore the contested flag,\n" +    "						@ and check whether that won." +    : [futex] "+&r" (futex), [flag] "+&r" (flag), [old] "=&r" (old) +    : : "memory" ); +#endif + +  return flag; +} +#define lll_mutex_trylock(lock)	__lll_mutex_trylock (&(lock)) + + +static inline int __attribute__((always_inline)) +__lll_mutex_cond_trylock (int *futex) +{ +  int flag = 2, old; +#ifdef __thumb__ +  old = atomic_exchange_acq (futex, flag); +  if (old < 1) +    flag = 0; +  else if (old > 1) +    flag = atomic_exchange_acq (futex, old); +#else +  __asm__ __volatile__ ( +    "\tswp	%[old], %[flag], [%[futex]]	@ try to take the lock\n" +    "\tcmp	%[old], #1			@ check old lock value\n" +    "\tmovlo	%[flag], #0			@ if we got it, return 0\n" +    "\tswphi	%[flag], %[old], [%[futex]]	@ if it was contested,\n" +    "						@ restore the contested flag,\n" +    "						@ and check whether that won." +    : [futex] "+&r" (futex), [flag] "+&r" (flag), [old] "=&r" (old) +    : : "memory" ); +#endif + +  return flag; +} +#define lll_mutex_cond_trylock(lock)	__lll_mutex_cond_trylock (&(lock)) + + +static inline int __attribute__((always_inline)) +__lll_robust_mutex_trylock(int *futex, int id) +{ +  return atomic_compare_and_exchange_val_acq (futex, id, 0) != 0; +} +#define lll_robust_mutex_trylock(lock, id) \ +  __lll_robust_mutex_trylock (&(lock), id) + +extern int __lll_robust_lock_wait (int *futex) attribute_hidden; + +static inline void __attribute__((always_inline)) +__lll_mutex_lock (int *futex) +{ +  int val = atomic_exchange_acq (futex, 1); + +  if (__builtin_expect (val != 0, 0)) +    { +      while (atomic_exchange_acq (futex, 2) != 0) +	lll_futex_wait (futex, 2); +    } +} +#define lll_mutex_lock(futex) __lll_mutex_lock (&(futex)) + + +static inline int __attribute__ ((always_inline)) +__lll_robust_mutex_lock (int *futex, int id) +{ +  int result = 0; +  if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0) +    result = __lll_robust_lock_wait (futex); +  return result; +} +#define lll_robust_mutex_lock(futex, id) \ +  __lll_robust_mutex_lock (&(futex), id) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_cond_lock (int *futex) +{ +  int val = atomic_exchange_acq (futex, 2); + +  if (__builtin_expect (val != 0, 0)) +    { +      while (atomic_exchange_acq (futex, 2) != 0) +	lll_futex_wait (futex, 2); +    } +} +#define lll_mutex_cond_lock(futex) __lll_mutex_cond_lock (&(futex)) + + +#define lll_robust_mutex_cond_lock(futex, id) \ +  __lll_robust_mutex_lock (&(futex), (id) | FUTEX_WAITERS) + + +extern int __lll_timedlock_wait (int *futex, const struct timespec *) +	attribute_hidden; +extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *) +	attribute_hidden; + +static inline int __attribute__ ((always_inline)) +__lll_mutex_timedlock (int *futex, const struct timespec *abstime) +{ +  int result = 0; +  int val = atomic_exchange_acq (futex, 1); + +  if (__builtin_expect (val != 0, 0)) +    result = __lll_timedlock_wait (futex, abstime); +  return result; +} +#define lll_mutex_timedlock(futex, abstime) \ +  __lll_mutex_timedlock (&(futex), abstime) + + +static inline int __attribute__ ((always_inline)) +__lll_robust_mutex_timedlock (int *futex, const struct timespec *abstime, +			      int id) +{ +  int result = 0; +  if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0) +    result = __lll_robust_timedlock_wait (futex, abstime); +  return result; +} +#define lll_robust_mutex_timedlock(futex, abstime, id) \ +  __lll_robust_mutex_timedlock (&(futex), abstime, id) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_unlock (int *futex) +{ +  int val = atomic_exchange_rel (futex, 0); +  if (__builtin_expect (val > 1, 0)) +    lll_futex_wake (futex, 1); +} +#define lll_mutex_unlock(futex) __lll_mutex_unlock(&(futex)) + + +static inline void __attribute__ ((always_inline)) +__lll_robust_mutex_unlock (int *futex, int mask) +{ +  int val = atomic_exchange_rel (futex, 0); +  if (__builtin_expect (val & mask, 0)) +    lll_futex_wake (futex, 1); +} +#define lll_robust_mutex_unlock(futex) \ +  __lll_robust_mutex_unlock(&(futex), FUTEX_WAITERS) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_unlock_force (int *futex) +{ +  (void) atomic_exchange_rel (futex, 0); +  lll_futex_wake (futex, 1); +} +#define lll_mutex_unlock_force(futex) __lll_mutex_unlock_force(&(futex)) + + +#define lll_mutex_islocked(futex) \ +  (futex != 0) + + +/* Our internal lock implementation is identical to the binary-compatible +   mutex implementation. */ + +/* Type for lock object.  */ +typedef int lll_lock_t; + +/* Initializers for lock.  */ +#define LLL_LOCK_INITIALIZER		(0) +#define LLL_LOCK_INITIALIZER_LOCKED	(1) + +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + +/* The states of a lock are: +    0  -  untaken +    1  -  taken by one user +   >1  -  taken by more users */ + +#define lll_trylock(lock)	lll_mutex_trylock (lock) +#define lll_lock(lock)		lll_mutex_lock (lock) +#define lll_unlock(lock)	lll_mutex_unlock (lock) +#define lll_islocked(lock)	lll_mutex_islocked (lock) + +/* 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);	\ +  } 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;						\ +  }) + + +/* Conditional variable handling.  */ + +extern void __lll_cond_wait (pthread_cond_t *cond) +     attribute_hidden; +extern int __lll_cond_timedwait (pthread_cond_t *cond, +				 const struct timespec *abstime) +     attribute_hidden; +extern void __lll_cond_wake (pthread_cond_t *cond) +     attribute_hidden; +extern void __lll_cond_broadcast (pthread_cond_t *cond) +     attribute_hidden; + +#define lll_cond_wait(cond) \ +  __lll_cond_wait (cond) +#define lll_cond_timedwait(cond, abstime) \ +  __lll_cond_timedwait (cond, abstime) +#define lll_cond_wake(cond) \ +  __lll_cond_wake (cond) +#define lll_cond_broadcast(cond) \ +  __lll_cond_broadcast (cond) + +#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..c8925810c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pthread_once.c @@ -0,0 +1,99 @@ +/* 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); +} + +int +__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); +    } + +  /* 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); + +  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..350d9af50 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h @@ -0,0 +1,153 @@ +/* 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 + +/* NOTE: We do mark syscalls with unwind annotations, for the benefit of +   cancellation; but they're really only accurate at the point of the +   syscall.  The ARM unwind directives are not rich enough without adding +   a custom personality function.  */ + +# 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:							\ +    .fnstart;								\ +    DOCARGS_##args;	/* save syscall args etc. around CENABLE.  */	\ +    CENABLE;								\ +    mov ip, r0;		/* put mask in safe place.  */			\ +    UNDOCARGS_##args;	/* restore syscall args.  */			\ +    ldr r7, =SYS_ify (syscall_name);					\ +    swi 0x0;		/* do the call.  */				\ +    .fnend;		/* Past here we can't easily unwind.  */	\ +    mov r7, r0;		/* save syscall return value.  */		\ +    mov r0, ip;		/* get mask back.  */				\ +    CDISABLE;								\ +    mov r0, r7;		/* retrieve return value.  */			\ +    RESTORE_LR_##args;							\ +    UNDOARGS_##args;							\ +    cmn r0, $4096; + +/* DOARGS pushes four bytes on the stack for five arguments, eight bytes for +   six arguments, and nothing for fewer.  In order to preserve doubleword +   alignment, sometimes we must save an extra register.  */ + +# define RESTART_UNWIND .fnend; .fnstart; .save {r7, lr} + +# define DOCARGS_0	stmfd sp!, {r7, lr}; .save {r7, lr} +# define UNDOCARGS_0 +# define RESTORE_LR_0	ldmfd sp!, {r7, lr}; + +# define DOCARGS_1	stmfd sp!, {r0, r1, r7, lr}; .save {r7, lr}; .pad #8 +# define UNDOCARGS_1	ldr r0, [sp], #8; RESTART_UNWIND +# define RESTORE_LR_1	RESTORE_LR_0 + +# define DOCARGS_2	stmfd sp!, {r0, r1, r7, lr}; .save {r7, lr}; .pad #8 +# define UNDOCARGS_2	ldmfd sp!, {r0, r1}; RESTART_UNWIND +# define RESTORE_LR_2	RESTORE_LR_0 + +# define DOCARGS_3	stmfd sp!, {r0, r1, r2, r3, r7, lr}; .save {r7, lr}; .pad #16 +# define UNDOCARGS_3	ldmfd sp!, {r0, r1, r2, r3}; RESTART_UNWIND +# define RESTORE_LR_3	RESTORE_LR_0 + +# define DOCARGS_4	stmfd sp!, {r0, r1, r2, r3, r7, lr}; .save {r7, lr}; .pad #16 +# define UNDOCARGS_4	ldmfd sp!, {r0, r1, r2, r3}; RESTART_UNWIND +# define RESTORE_LR_4	RESTORE_LR_0 + +# define DOCARGS_5	.save {r4}; stmfd sp!, {r0, r1, r2, r3, r4, r7, lr}; .save {r7, lr}; .pad #20 +# define UNDOCARGS_5	ldmfd sp!, {r0, r1, r2, r3}; .fnend; .fnstart; .save {r4}; .save {r7, lr}; .pad #4 +# define RESTORE_LR_5	ldmfd sp!, {r4, r7, lr} + +# define DOCARGS_6	.save {r4, r5}; stmfd sp!, {r0, r1, r2, r3, r7, lr}; .save {r7, lr}; .pad #20 +# define UNDOCARGS_6	ldmfd sp!, {r0, r1, r2, r3}; .fnend; .fnstart; .save {r4, r5}; .save {r7, lr} +# define RESTORE_LR_6	RESTORE_LR_0 + +# 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 diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep.h new file mode 100644 index 000000000..23c2bfc8c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep.h @@ -0,0 +1,334 @@ +/* Copyright (C) 1992, 93, 1995-2000, 2002, 2003, 2005, 2006 +   Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>, August 1995. +   ARM changes by Philip Blundell, <pjb27@cam.ac.uk>, May 1997. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License 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 _LINUX_ARM_SYSDEP_H +#define _LINUX_ARM_SYSDEP_H 1 + +#include <sys/syscall.h> + +/* There is some commonality.  */ +#include <sysdeps/arm/sysdep.h> + +/* For Linux we can use the system call table in the header file +	/usr/include/asm/unistd.h +   of the kernel.  But these symbols do not follow the SYS_* syntax +   so we have to redefine the `SYS_ify' macro here.  */ +#undef SYS_ify +#define SWI_BASE  (0x900000) +#define SYS_ify(syscall_name)	(__NR_##syscall_name) + + +#ifdef __ASSEMBLER__ + +/* Linux uses a negative return value to indicate syscall errors, +   unlike most Unices, which use the condition codes' carry flag. + +   Since version 2.1 the return value of a system call might be +   negative even if the call succeeded.  E.g., the `lseek' system call +   might return a large offset.  Therefore we must not anymore test +   for < 0, but test for a real error by making sure the value in R0 +   is a real error number.  Linus said he will make sure the no syscall +   returns a value in -1 .. -4095 as a valid result so we can safely +   test with -4095.  */ + +#undef	PSEUDO +#define	PSEUDO(name, syscall_name, args)				      \ +  .text;								      \ +  ENTRY (name);								      \ +    DO_CALL (syscall_name, args);					      \ +    cmn r0, $4096; + +#define PSEUDO_RET							      \ +    RETINSTR(cc, lr);							      \ +    b PLTJMP(SYSCALL_ERROR) +#undef ret +#define ret PSEUDO_RET + +#undef	PSEUDO_END +#define	PSEUDO_END(name)						      \ +  SYSCALL_ERROR_HANDLER							      \ +  END (name) + +#undef	PSEUDO_NOERRNO +#define	PSEUDO_NOERRNO(name, syscall_name, args)			      \ +  .text;								      \ +  ENTRY (name);								      \ +    DO_CALL (syscall_name, args); + +#define PSEUDO_RET_NOERRNO						      \ +    DO_RET (lr); + +#undef ret_NOERRNO +#define ret_NOERRNO PSEUDO_RET_NOERRNO + +#undef	PSEUDO_END_NOERRNO +#define	PSEUDO_END_NOERRNO(name)					      \ +  END (name) + +/* The function has to return the error code.  */ +#undef	PSEUDO_ERRVAL +#define	PSEUDO_ERRVAL(name, syscall_name, args) \ +  .text;								      \ +  ENTRY (name)								      \ +    DO_CALL (syscall_name, args);					      \ +    rsb r0, r0, #0 + +#undef	PSEUDO_END_ERRVAL +#define	PSEUDO_END_ERRVAL(name) \ +  END (name) + +#define ret_ERRVAL PSEUDO_RET_NOERRNO + +#if NOT_IN_libc +# define SYSCALL_ERROR __local_syscall_error +# ifdef RTLD_PRIVATE_ERRNO +#  define SYSCALL_ERROR_HANDLER					\ +__local_syscall_error:						\ +       ldr     r1, 1f;						\ +       rsb     r0, r0, #0;					\ +0:     str     r0, [pc, r1];					\ +       mvn     r0, #0;						\ +       DO_RET(lr);						\ +1:     .word C_SYMBOL_NAME(rtld_errno) - 0b - 8; +# else +#  define SYSCALL_ERROR_HANDLER					\ +__local_syscall_error:						\ +	str	lr, [sp, #-4]!;					\ +	str	r0, [sp, #-4]!;					\ +	bl	PLTJMP(C_SYMBOL_NAME(__errno_location)); 	\ +	ldr	r1, [sp], #4;					\ +	rsb	r1, r1, #0;					\ +	str	r1, [r0];					\ +	mvn	r0, #0;						\ +	ldr	pc, [sp], #4; +# endif +#else +# define SYSCALL_ERROR_HANDLER	/* Nothing here; code in sysdep.S is used.  */ +# define SYSCALL_ERROR __syscall_error +#endif + +/* Linux takes system call args in registers: +	syscall number	in the SWI instruction +	arg 1		r0 +	arg 2		r1 +	arg 3		r2 +	arg 4		r3 +	arg 5		r4	(this is different from the APCS convention) +	arg 6		r5 +	arg 7		r6 + +   The compiler is going to form a call by coming here, through PSEUDO, with +   arguments +	syscall number	in the DO_CALL macro +	arg 1		r0 +	arg 2		r1 +	arg 3		r2 +	arg 4		r3 +	arg 5		[sp] +	arg 6		[sp+4] +	arg 7		[sp+8] + +   We need to shuffle values between R4..R6 and the stack so that the +   caller's v1..v3 and stack frame are not corrupted, and the kernel +   sees the right arguments. + +*/ + +#undef	DO_CALL +#if defined(__ARM_EABI__) +#define DO_CALL(syscall_name, args)		\ +    DOARGS_##args				\ +    mov ip, r7;					\ +    ldr r7, =SYS_ify (syscall_name);		\ +    swi 0x0;					\ +    mov r7, ip;					\ +    UNDOARGS_##args +#else +#define DO_CALL(syscall_name, args)		\ +    DOARGS_##args				\ +    swi SYS_ify (syscall_name); 		\ +    UNDOARGS_##args +#endif + +#define DOARGS_0 /* nothing */ +#define DOARGS_1 /* nothing */ +#define DOARGS_2 /* nothing */ +#define DOARGS_3 /* nothing */ +#define DOARGS_4 /* nothing */ +#define DOARGS_5 str r4, [sp, $-4]!; ldr r4, [sp, $4]; +#define DOARGS_6 mov ip, sp; stmfd sp!, {r4, r5}; ldmia ip, {r4, r5}; +#define DOARGS_7 mov ip, sp; stmfd sp!, {r4, r5, r6}; ldmia ip, {r4, r5, r6}; + +#define UNDOARGS_0 /* nothing */ +#define UNDOARGS_1 /* nothing */ +#define UNDOARGS_2 /* nothing */ +#define UNDOARGS_3 /* nothing */ +#define UNDOARGS_4 /* nothing */ +#define UNDOARGS_5 ldr r4, [sp], $4; +#define UNDOARGS_6 ldmfd sp!, {r4, r5}; +#define UNDOARGS_7 ldmfd sp!, {r4, r5, r6}; + +#else /* not __ASSEMBLER__ */ + +/* Define a macro which expands into the inline wrapper code for a system +   call.  */ +#undef INLINE_SYSCALL +#define INLINE_SYSCALL(name, nr, args...)				\ +  ({ unsigned int _sys_result = INTERNAL_SYSCALL (name, , nr, args);	\ +     if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_sys_result, ), 0))	\ +       {								\ +	 __set_errno (INTERNAL_SYSCALL_ERRNO (_sys_result, ));		\ +	 _sys_result = (unsigned int) -1;				\ +       }								\ +     (int) _sys_result; }) + +#undef INTERNAL_SYSCALL_DECL +#define INTERNAL_SYSCALL_DECL(err) do { } while (0) + +#undef INTERNAL_SYSCALL_RAW +#if defined(__thumb__) +/* Hide the use of r7 from the compiler, this would be a lot + * easier but for the fact that the syscalls can exceed 255. + * For the moment the LOAD_ARG_7 is sacrificed. + * We can't use push/pop inside the asm because that breaks + * unwinding (ie. thread cancellation). + */ +#define INTERNAL_SYSCALL_RAW(name, err, nr, args...)		\ +  ({ unsigned int _sys_result;                                  \ +    {                                                           \ +      int _sys_buf[2];						\ +      register int _a1 __asm__ ("a1");                          \ +      register int *_v3 __asm__ ("v3") = _sys_buf;		\ +      LOAD_ARGS_##nr (args)                                     \ +      *_v3 = (int) (name);					\ +      __asm__ __volatile__ ("str	r7, [v3, #4]\n"		\ +                    "\tldr      r7, [v3]\n"                     \ +                    "\tswi      0       @ syscall " #name "\n"  \ +                    "\tldr      r7, [v3, #4]"                   \ +                   : "=r" (_a1)                                 \ +                    : "r" (_v3) ASM_ARGS_##nr                   \ +                    : "memory");                                \ +      _sys_result = _a1;                                        \ +    }                                                           \ +    (int) _sys_result; }) +#elif defined(__ARM_EABI__) +#define INTERNAL_SYSCALL_RAW(name, err, nr, args...)		\ +  ({unsigned int _sys_result;					\ +     {								\ +       register int _a1 __asm__ ("r0"), _nr __asm__ ("r7");	\ +       LOAD_ARGS_##nr (args)					\ +       _nr = name;						\ +       __asm__ __volatile__ ("swi	0x0 @ syscall " #name	\ +		     : "=r" (_a1)				\ +		     : "r" (_nr) ASM_ARGS_##nr			\ +		     : "memory");				\ +       _sys_result = _a1;					\ +     }								\ +     (int) _sys_result; }) +#else /* !defined(__ARM_EABI__) */ +#define INTERNAL_SYSCALL_RAW(name, err, nr, args...)		\ +  ({ unsigned int _sys_result;					\ +     {								\ +       register int _a1 __asm__ ("a1");				\ +       LOAD_ARGS_##nr (args)					\ +       __asm__ __volatile__ ("swi	%1 @ syscall " #name	\ +		     : "=r" (_a1)				\ +		     : "i" (name) ASM_ARGS_##nr			\ +		     : "memory");				\ +       _sys_result = _a1;					\ +     }								\ +     (int) _sys_result; }) +#endif + +#undef INTERNAL_SYSCALL +#define INTERNAL_SYSCALL(name, err, nr, args...)		\ +	INTERNAL_SYSCALL_RAW(SYS_ify(name), err, nr, args) + +#undef INTERNAL_SYSCALL_ARM +#define INTERNAL_SYSCALL_ARM(name, err, nr, args...)		\ +	INTERNAL_SYSCALL_RAW(__ARM_NR_##name, err, nr, args) + +#undef INTERNAL_SYSCALL_ERROR_P +#define INTERNAL_SYSCALL_ERROR_P(val, err) \ +  ((unsigned int) (val) >= 0xfffff001u) + +#undef INTERNAL_SYSCALL_ERRNO +#define INTERNAL_SYSCALL_ERRNO(val, err)	(-(val)) + +#define LOAD_ARGS_0() +#define ASM_ARGS_0 +#define LOAD_ARGS_1(a1)				\ +  _a1 = (int) (a1);				\ +  LOAD_ARGS_0 () +#define ASM_ARGS_1	ASM_ARGS_0, "r" (_a1) +#define LOAD_ARGS_2(a1, a2)			\ +  register int _a2 __asm__ ("a2") = (int) (a2);	\ +  LOAD_ARGS_1 (a1) +#define ASM_ARGS_2	ASM_ARGS_1, "r" (_a2) +#define LOAD_ARGS_3(a1, a2, a3)			\ +  register int _a3 __asm__ ("a3") = (int) (a3);	\ +  LOAD_ARGS_2 (a1, a2) +#define ASM_ARGS_3	ASM_ARGS_2, "r" (_a3) +#define LOAD_ARGS_4(a1, a2, a3, a4)		\ +  register int _a4 __asm__ ("a4") = (int) (a4);	\ +  LOAD_ARGS_3 (a1, a2, a3) +#define ASM_ARGS_4	ASM_ARGS_3, "r" (_a4) +#define LOAD_ARGS_5(a1, a2, a3, a4, a5)		\ +  register int _v1 __asm__ ("v1") = (int) (a5);	\ +  LOAD_ARGS_4 (a1, a2, a3, a4) +#define ASM_ARGS_5	ASM_ARGS_4, "r" (_v1) +#define LOAD_ARGS_6(a1, a2, a3, a4, a5, a6)	\ +  register int _v2 __asm__ ("v2") = (int) (a6);	\ +  LOAD_ARGS_5 (a1, a2, a3, a4, a5) +#define ASM_ARGS_6	ASM_ARGS_5, "r" (_v2) +#define LOAD_ARGS_7(a1, a2, a3, a4, a5, a6, a7)	\ +  register int _v3 __asm__ ("v3") = (int) (a7);	\ +  LOAD_ARGS_6 (a1, a2, a3, a4, a5, a6) +#define ASM_ARGS_7	ASM_ARGS_6, "r" (_v3) + +#if defined(__ARM_EABI__) +#undef INTERNAL_SYSCALL_NCS +#define INTERNAL_SYSCALL_NCS(number, err, nr, args...)		\ +	INTERNAL_SYSCALL_RAW(number, err, nr, args) +#else +/* We can't implement non-constant syscalls directly since the syscall +   number is normally encoded in the instruction.  So use SYS_syscall.  */ +#undef INTERNAL_SYSCALL_NCS +#define INTERNAL_SYSCALL_NCS(number, err, nr, args...)		\ +	INTERNAL_SYSCALL_NCS_##nr (number, err, args) + +#define INTERNAL_SYSCALL_NCS_0(number, err, args...)		\ +	INTERNAL_SYSCALL (syscall, err, 1, number, args) +#define INTERNAL_SYSCALL_NCS_1(number, err, args...)		\ +	INTERNAL_SYSCALL (syscall, err, 2, number, args) +#define INTERNAL_SYSCALL_NCS_2(number, err, args...)		\ +	INTERNAL_SYSCALL (syscall, err, 3, number, args) +#define INTERNAL_SYSCALL_NCS_3(number, err, args...)		\ +	INTERNAL_SYSCALL (syscall, err, 4, number, args) +#define INTERNAL_SYSCALL_NCS_4(number, err, args...)		\ +	INTERNAL_SYSCALL (syscall, err, 5, number, args) +#define INTERNAL_SYSCALL_NCS_5(number, err, args...)		\ +	INTERNAL_SYSCALL (syscall, err, 6, number, args) +#endif + +#endif	/* __ASSEMBLER__ */ + +#endif /* linux/arm/sysdep.h */ 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..206202809 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c @@ -0,0 +1,129 @@ +/* Copyright (C) 2003, 2005 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 <string.h> +#include <unwind.h> +#include <unistd.h> +#include <pthreadP.h> + +#define __libc_dlopen(x)	dlopen(x, (RTLD_LOCAL | RTLD_LAZY)) +#define __libc_dlsym		dlsym + +static void (*libgcc_s_resume) (struct _Unwind_Exception *exc); +static _Unwind_Reason_Code (*libgcc_s_personality) +  (_Unwind_State, 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 *); + +void +pthread_cancel_init (void) +{ +  void *resume, *personality, *forcedunwind, *getcfa; +  void *handle; + +  if (__builtin_expect (libgcc_s_getcfa != NULL, 1)) +    return; + +  handle = __libc_dlopen ("libgcc_s.so.1"); + +  if (handle == NULL +      || (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL +      || (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL +      || (forcedunwind = __libc_dlsym (handle, "_Unwind_ForcedUnwind")) +	 == NULL +      || (getcfa = __libc_dlsym (handle, "_Unwind_GetCFA")) == NULL +#ifdef ARCH_CANCEL_INIT +      || ARCH_CANCEL_INIT (handle) +#endif +      ) +    { +# define STR_N_LEN(str) str, strlen (str) +      INTERNAL_SYSCALL_DECL (err); +      INTERNAL_SYSCALL (write, err, 3, STDERR_FILENO, +			STR_N_LEN ("libgcc_s.so.1 must be installed for pthread_cancel to work\n")); +      abort (); +    } + +  libgcc_s_resume = resume; +  libgcc_s_personality = personality; +  libgcc_s_forcedunwind = forcedunwind; +  libgcc_s_getcfa = getcfa; +} + +/* It's vitally important that _Unwind_Resume not have a stack frame; the +   ARM unwinder relies on register state at entrance.  So we write this in +   assembly.  */ + +asm ( +#ifdef __thumb__ +"	.code 32" +#endif +"	.globl	_Unwind_Resume\n" +"	.type	_Unwind_Resume, %function\n" +"_Unwind_Resume:\n" +"	stmfd	sp!, {r4, r5, r6, lr}\n" +"	ldr	r4, 1f\n" +"	ldr	r5, 2f\n" +"3:	add	r4, pc, r4\n" +"	ldr	r3, [r4, r5]\n" +"	mov	r6, r0\n" +"	cmp	r3, #0\n" +"	beq	4f\n" +"5:	mov	r0, r6\n" +"	ldmfd	sp!, {r4, r5, r6, lr}\n" +"	bx	r3\n" +"4:	bl	pthread_cancel_init\n" +"	ldr	r3, [r4, r5]\n" +"	b	5b\n" +"1:	.word	_GLOBAL_OFFSET_TABLE_ - 3b - 8\n" +"2:	.word	libgcc_s_resume(GOTOFF)\n" +"	.size	_Unwind_Resume, .-_Unwind_Resume\n" +#ifdef __thumb__ +"	.code 16" +#endif +); + +_Unwind_Reason_Code +__gcc_personality_v0 (_Unwind_State state, +		      struct _Unwind_Exception *ue_header, +		      struct _Unwind_Context *context) +{ +  if (__builtin_expect (libgcc_s_personality == NULL, 0)) +    pthread_cancel_init (); +  return libgcc_s_personality (state, 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); +} 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..99b15746a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-resume.c @@ -0,0 +1,95 @@ +/* Copyright (C) 2003, 2005 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 <stdlib.h> +#include <unwind.h> + +#define __libc_dlopen(x)	dlopen(x, (RTLD_LOCAL | RTLD_LAZY)) +#define __libc_dlsym		dlsym + +static void (*libgcc_s_resume) (struct _Unwind_Exception *exc); +static _Unwind_Reason_Code (*libgcc_s_personality) +  (_Unwind_State, struct _Unwind_Exception *, struct _Unwind_Context *); + +static void init (void) __attribute_used__; + +static void +init (void) +{ +  void *resume, *personality; +  void *handle; + +  handle = __libc_dlopen ("libgcc_s.so.1"); + +  if (handle == NULL +      || (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL +      || (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL) { +    fprintf(stderr, "libgcc_s.so.1 must be installed for pthread_cancel to work\n"); +    abort (); +  } + +  libgcc_s_resume = resume; +  libgcc_s_personality = personality; +} + +/* It's vitally important that _Unwind_Resume not have a stack frame; the +   ARM unwinder relies on register state at entrance.  So we write this in +   assembly.  */ + +__asm__ ( +#ifdef __thumb__ +"       .code 32\n" +#endif +"	.globl	_Unwind_Resume\n" +"	.type	_Unwind_Resume, %function\n" +"_Unwind_Resume:\n" +"	stmfd	sp!, {r4, r5, r6, lr}\n" +"	ldr	r4, 1f\n" +"	ldr	r5, 2f\n" +"3:	add	r4, pc, r4\n" +"	ldr	r3, [r4, r5]\n" +"	mov	r6, r0\n" +"	cmp	r3, #0\n" +"	beq	4f\n" +"5:	mov	r0, r6\n" +"	ldmfd	sp!, {r4, r5, r6, lr}\n" +"	bx	r3\n" +"4:	bl	init\n" +"	ldr	r3, [r4, r5]\n" +"	b	5b\n" +"1:	.word	_GLOBAL_OFFSET_TABLE_ - 3b - 8\n" +"2:	.word	libgcc_s_resume(GOTOFF)\n" +"	.size	_Unwind_Resume, .-_Unwind_Resume\n" +#ifdef __thumb__ +"       .code 16\n" +#endif + +); + +_Unwind_Reason_Code +__gcc_personality_v0 (_Unwind_State state, +		      struct _Unwind_Exception *ue_header, +		      struct _Unwind_Context *context) +{ +  if (__builtin_expect (libgcc_s_personality == NULL, 0)) +    init (); +  return libgcc_s_personality (state, ue_header, context); +} 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..d625fb288 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind.h @@ -0,0 +1,274 @@ +/* Header file for the ARM EABI unwinder +   Copyright (C) 2003, 2004, 2005  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)) + +#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..b639ba44a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/bits/local_lim.h @@ -0,0 +1,89 @@ +/* Minimum guaranteed maximum values for system limits.  Linux version. +   Copyright (C) 1993-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; 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 + +/* 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 + +/* 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 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..92c2d3282 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h @@ -0,0 +1,178 @@ +/* Define POSIX options for Linux. +   Copyright (C) 1996-2001, 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; 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	_POSIX_OPT_H +#define	_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	200112L + +/* Synchronizing file data is supported.  */ +#define	_POSIX_SYNCHRONIZED_IO	200112L + +/* The fsync function is present.  */ +#define	_POSIX_FSYNC	200112L + +/* Mapping of files to memory is supported.  */ +#define	_POSIX_MAPPED_FILES	200112L + +/* Locking of all memory is supported.  */ +#define	_POSIX_MEMLOCK	200112L + +/* Locking of ranges of memory is supported.  */ +#define	_POSIX_MEMLOCK_RANGE	200112L + +/* Setting of memory protections is supported.  */ +#define	_POSIX_MEMORY_PROTECTION	200112L + +/* Only root can change owner of file.  */ +#define	_POSIX_CHOWN_RESTRICTED	1 + +/* `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 + +/* XPG4.2 shared memory is supported.  */ +#define	_XOPEN_SHM	1 + +/* Tell we have POSIX threads.  */ +#define _POSIX_THREADS	200112L + +/* We have the reentrant functions described in POSIX.  */ +#define _POSIX_REENTRANT_FUNCTIONS      1 +#define _POSIX_THREAD_SAFE_FUNCTIONS	200112L + +/* We provide priority scheduling for threads.  */ +#define _POSIX_THREAD_PRIORITY_SCHEDULING	200112L + +/* We support user-defined stack sizes.  */ +#define _POSIX_THREAD_ATTR_STACKSIZE	200112L + +/* We support user-defined stacks.  */ +#define _POSIX_THREAD_ATTR_STACKADDR	200112L + +/* We support POSIX.1b semaphores.  */ +#define _POSIX_SEMAPHORES	200112L + +/* Real-time signals are supported.  */ +#define _POSIX_REALTIME_SIGNALS	200112L + +/* We support asynchronous I/O.  */ +#define _POSIX_ASYNCHRONOUS_IO	200112L +#define _POSIX_ASYNC_IO		1 +/* Alternative name for Unix98.  */ +#define _LFS_ASYNCHRONOUS_IO	1 +/* Support for prioritization is also available.  */ +#define _POSIX_PRIORITIZED_IO	200112L + +/* 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	200112L + +/* 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	200112L + +/* We have a POSIX shell.  */ +#define _POSIX_SHELL	1 + +/* We support the Timeouts option.  */ +#define _POSIX_TIMEOUTS	200112L + +/* We support spinlocks.  */ +#define _POSIX_SPIN_LOCKS	200112L + +/* The `spawn' function family is supported.  */ +#define _POSIX_SPAWN	200112L + +/* We have POSIX timers.  */ +#define _POSIX_TIMERS	200112L + +/* The barrier functions are available.  */ +#define _POSIX_BARRIERS	200112L + +/* POSIX message queues are available.  */ +#define	_POSIX_MESSAGE_PASSING	200112L + +/* Thread process-shared synchronization is supported.  */ +#define _POSIX_THREAD_PROCESS_SHARED	200112L + +/* The monotonic clock might be available.  */ +#define _POSIX_MONOTONIC_CLOCK	0 + +/* The clock selection interfaces are available.  */ +#define _POSIX_CLOCK_SELECTION	200112L + +/* Advisory information interfaces are available.  */ +#define _POSIX_ADVISORY_INFO	200112L + +/* IPv6 support is available.  */ +#define _POSIX_IPV6	200112L + +/* Raw socket support is available.  */ +#define _POSIX_RAW_SOCKETS	200112L + +/* We have at least one terminal.  */ +#define _POSIX2_CHAR_TERM	200112L + +/* 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 + +/* No support for priority inheritance or protection so far.  */ +#define _POSIX_THREAD_PRIO_INHERIT	-1 +#define _POSIX_THREAD_PRIO_PROTECT	-1 + +#endif /* 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..a84b5c237 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/fork.c @@ -0,0 +1,220 @@ +/* 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 <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 +} + +extern __typeof(fork) __libc_fork; +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) +    { +      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); + +      /* 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.  */ +	  --allp->handler->refcntr; + +	  /* 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_t) 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); + +	  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..bcdf6217c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/fork.h @@ -0,0 +1,56 @@ +/* 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 <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 lll_lock_t __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; + + +/* 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); 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..9a4f51c9d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/getpid.c @@ -0,0 +1,63 @@ +/* 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> + + +extern __typeof(getpid) __getpid; +#ifndef NOT_IN_libc +static __always_inline pid_t really_getpid (pid_t oldval); + +static __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..740ee7fcb --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/Makefile.arch @@ -0,0 +1,74 @@ +# 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 + + +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/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 + +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-pthread_spin_unlock.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 +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/i386/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h new file mode 100644 index 000000000..0ec6e5534 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h @@ -0,0 +1,170 @@ +/* Copyright (C) 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.  */ + +#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 int __flags; +    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..e6c5d845c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/bits/semaphore.h @@ -0,0 +1,39 @@ +/* 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) + +/* Maximum value the semaphore can have.  */ +#define SEM_VALUE_MAX   (2147483647) + + +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..b874538b3 --- /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 <stdio.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..223b11108 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/libc-lowlevellock.S @@ -0,0 +1,30 @@ +/* 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.  */ + +/* In libc.so we do not unconditionally use the lock prefix.  Only if +   the application is using threads.  */ +#ifndef UP +# define LOCK \ +	cmpl	$0, %gs:MULTIPLE_THREADS_OFFSET; 			      \ +	je,pt	0f;							      \ +	lock;								      \ +0: +#endif + +#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..955e119ab --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S @@ -0,0 +1,283 @@ +/* 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 <sysdep.h> +#include <pthread-errnos.h> + +	.text + +#ifndef LOCK +# ifdef UP +#  define LOCK +# else +#  define LOCK lock +# endif +#endif + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + + +	.globl	__lll_mutex_lock_wait +	.type	__lll_mutex_lock_wait,@function +	.hidden	__lll_mutex_lock_wait +	.align	16 +__lll_mutex_lock_wait: +	pushl	%edx +	pushl	%ebx +	pushl	%esi + +	movl	$2, %edx +	movl	%ecx, %ebx +	xorl	%esi, %esi	/* No timeout.  */ +	xorl	%ecx, %ecx	/* movl $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,pn	1b + +	popl	%esi +	popl	%ebx +	popl	%edx +	ret +	.size	__lll_mutex_lock_wait,.-__lll_mutex_lock_wait + + +#ifdef NOT_IN_libc +	.globl	__lll_mutex_timedlock_wait +	.type	__lll_mutex_timedlock_wait,@function +	.hidden	__lll_mutex_timedlock_wait +	.align	16 +__lll_mutex_timedlock_wait: +	/* Check for a valid timeout value.  */ +	cmpl	$1000000000, 4(%edx) +	jae	3f + +	pushl	%edi +	pushl	%esi +	pushl	%ebx +	pushl	%ebp + +	/* Stack frame for the timespec and timeval structs.  */ +	subl	$8, %esp + +	movl	%ecx, %ebp +	movl	%edx, %edi + +1: +	/* Get current time.  */ +	movl	%esp, %ebx +	xorl	%ecx, %ecx +	movl	$SYS_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	5f		/* Time is already up.  */ + +	/* Store relative timeout.  */ +	movl	%ecx, (%esp) +	movl	%edx, 4(%esp) + +	movl	%ebp, %ebx + +	movl	$1, %eax +	movl	$2, %edx +	LOCK +	cmpxchgl %edx, (%ebx) + +	testl	%eax, %eax +	je	8f + +	/* Futex call.  */ +	movl	%esp, %esi +	xorl	%ecx, %ecx	/* movl $FUTEX_WAIT, %ecx */ +	movl	$SYS_futex, %eax +	ENTER_KERNEL +	movl	%eax, %ecx + +8:				/* NB: %edx == 2 */ +	xorl	%eax, %eax +	LOCK +	cmpxchgl %edx, (%ebx) + +	jnz	7f + +6:	addl	$8, %esp +	popl	%ebp +	popl	%ebx +	popl	%esi +	popl	%edi +	ret + +	/* Check whether the time expired.  */ +7:	cmpl	$-ETIMEDOUT, %ecx +	je	5f + +	/* Make sure the current holder knows we are going to sleep.  */ +	movl	%edx, %eax +	xchgl	%eax, (%ebx) +	testl	%eax, %eax +	jz	6b +	jmp	1b + +3:	movl	$EINVAL, %eax +	ret + +5:	movl	$ETIMEDOUT, %eax +	jmp	6b +	.size	__lll_mutex_timedlock_wait,.-__lll_mutex_timedlock_wait +#endif + + +#ifdef NOT_IN_libc +	.globl	lll_unlock_wake_cb +	.type	lll_unlock_wake_cb,@function +	.hidden	lll_unlock_wake_cb +	.align	16 +lll_unlock_wake_cb: +	pushl	%ebx +	pushl	%ecx +	pushl	%edx + +	movl	20(%esp), %ebx +	LOCK +	subl	$1, (%ebx) +	je	1f + +	movl	$FUTEX_WAKE, %ecx +	movl	$1, %edx	/* Wake one thread.  */ +	movl	$SYS_futex, %eax +	movl	$0, (%ebx) +	ENTER_KERNEL + +1:	popl	%edx +	popl	%ecx +	popl	%ebx +	ret +	.size	lll_unlock_wake_cb,.-lll_unlock_wake_cb +#endif + + +	.globl	__lll_mutex_unlock_wake +	.type	__lll_mutex_unlock_wake,@function +	.hidden	__lll_mutex_unlock_wake +	.align	16 +__lll_mutex_unlock_wake: +	pushl	%ebx +	pushl	%ecx +	pushl	%edx + +	movl	%eax, %ebx +	movl	$0, (%eax) +	movl	$FUTEX_WAKE, %ecx +	movl	$1, %edx	/* Wake one thread.  */ +	movl	$SYS_futex, %eax +	ENTER_KERNEL + +	popl	%edx +	popl	%ecx +	popl	%ebx +	ret +	.size	__lll_mutex_unlock_wake,.-__lll_mutex_unlock_wake + + +#ifdef NOT_IN_libc +	.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	$SYS_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 +	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/pthread_barrier_wait.S b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S new file mode 100644 index 000000000..2af9e38cd --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S @@ -0,0 +1,162 @@ +/* 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 <sysdep.h> +#include <lowlevelbarrier.h> + +#define FUTEX_WAIT	0 +#define FUTEX_WAKE	1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + +	.text + +	.globl	pthread_barrier_wait +	.type	pthread_barrier_wait,@function +	.align	16 +pthread_barrier_wait: +	pushl	%ebx + +	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 + +#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:	xorl	%ecx, %ecx		/* movl $FUTEX_WAIT, %ecx */ +	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,pn	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,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 +	subl	$1, MUTEX(%ebx) +	jne	9f + +	/* Note: %esi is still zero.  */ +10:	movl	%esi, %eax		/* != PTHREAD_BARRIER_SERIAL_THREAD */ + +	popl	%esi +	popl	%ebx +	ret + +	/* 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 +	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,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 +	subl	$1, MUTEX(%ebx) +	jne	4f + +5:	orl	$-1, %eax		/* == PTHREAD_BARRIER_SERIAL_THREAD */ + +	popl	%ebx +	ret + +1:	leal	MUTEX(%ebx), %ecx +	call	__lll_mutex_lock_wait +	jmp	2b + +4:	leal	MUTEX(%ebx), %eax +	call	__lll_mutex_unlock_wake +	jmp	5b + +6:	leal	MUTEX(%ebx), %eax +	call	__lll_mutex_unlock_wake +	jmp	7b + +9:	leal	MUTEX(%ebx), %eax +	call	__lll_mutex_unlock_wake +	jmp	10b +	.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..6e8ffe6f6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S @@ -0,0 +1,161 @@ +/* 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 <sysdep.h> +#include <lowlevelcond.h> +#include <bits/kernel-features.h> + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 +#define FUTEX_REQUEUE		3 +#define FUTEX_CMP_REQUEUE	4 + +#define EINVAL			22 + + +	.text + +	/* int pthread_cond_broadcast (pthread_cond_t *cond) */ +	.globl	__pthread_cond_broadcast +	.type	__pthread_cond_broadcast, @function +	.align	16 +__pthread_cond_broadcast: + +	pushl	%ebx +	pushl	%esi +	pushl	%edi +	pushl	%ebp + +	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 + +	/* Wake up all threads.  */ +	movl	$FUTEX_CMP_REQUEUE, %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 +/* 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 + +10:	xorl	%eax, %eax +	popl	%ebp +	popl	%edi +	popl	%esi +	popl	%ebx +	ret + +	.align	16 +	/* Unlock.  */ +4:	LOCK +	subl	$1, cond_lock-cond_futex(%ebx) +	jne	5f + +6:	xorl	%eax, %eax +	popl	%ebp +	popl	%edi +	popl	%esi +	popl	%ebx +	ret + +	/* Initial locking failed.  */ +1: +#if cond_lock == 0 +	movl	%ebx, %ecx +#else +	leal	cond_lock(%ebx), %ecx +#endif +	call	__lll_mutex_lock_wait +	jmp	2b + +	/* Unlock in loop requires waekup.  */ +5:	leal	cond_lock-cond_futex(%ebx), %eax +	call	__lll_mutex_unlock_wake +	jmp	6b + +	/* Unlock in loop requires waekup.  */ +7:	leal	cond_lock-cond_futex(%ebx), %eax +	call	__lll_mutex_unlock_wake +	jmp	8b + +9:	/* The futex requeue functionality is not available.  */ +	movl	$0x7fffffff, %edx +	movl	$FUTEX_WAKE, %ecx +	movl	$SYS_futex, %eax +	ENTER_KERNEL +	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/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..ec8217987 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_signal.S @@ -0,0 +1,111 @@ +/* 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 <sysdep.h> +#include <lowlevelcond.h> +#include <bits/kernel-features.h> + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 +#define FUTEX_REQUEUE		3 + +#define EINVAL			22 + + +	.text + +	/* int pthread_cond_signal (pthread_cond_t *cond) */ +	.globl	__pthread_cond_signal +	.type	__pthread_cond_signal, @function +	.align	16 +__pthread_cond_signal: + +	pushl	%ebx +	pushl	%edi + +	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.  */ +	movl	$FUTEX_WAKE, %ecx +	movl	$SYS_futex, %eax +	movl	$1, %edx +	ENTER_KERNEL + +	/* Unlock.  Note that at this point %edi always points to +	   cond_lock.  */ +4:	LOCK +	subl	$1, (%edi) +	jne	5f + +6:	xorl	%eax, %eax +	popl	%edi +	popl	%ebx +	ret + +	/* Initial locking failed.  */ +1: +#if cond_lock == 0 +	movl	%edi, %ecx +#else +	leal	cond_lock(%edi), %ecx +#endif +	call	__lll_mutex_lock_wait +	jmp	2b + +	/* Unlock in loop requires wakeup.  */ +5:	movl	%edi, %eax +	call	__lll_mutex_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/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..b8f0d2e4b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S @@ -0,0 +1,465 @@ +/* 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 <sysdep.h> +#include <lowlevelcond.h> +#include <pthread-errnos.h> + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + + +	.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 +	.align	16 +__pthread_cond_timedwait: +.LSTARTCODE: +	pushl	%ebp +.Lpush_ebp: +	pushl	%edi +.Lpush_edi: +	pushl	%esi +.Lpush_esi: +	pushl	%ebx +.Lpush_ebx: + +	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 << clock_bits), cond_nwaiters(%ebx) + +#define FRAME_SIZE 24 +	subl	$FRAME_SIZE, %esp +.Lsubl: + +	/* 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) + +	/* Get the current time.  */ +8:	movl	%ebx, %edx +#ifdef __NR_clock_gettime +	/* Get the clock number.  */ +	movl	cond_nwaiters(%ebx), %ebx +	andl	$((1 << clock_bits) - 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	$SYS_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 + +	/* 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) + +	leal	4(%esp), %esi +	xorl	%ecx, %ecx	/* movl $FUTEX_WAIT, %ecx */ +	movl	%edi, %edx +	addl	$cond_futex, %ebx +.Ladd_cond_futex: +	movl	$SYS_futex, %eax +	ENTER_KERNEL +	subl	$cond_futex, %ebx +.Lsub_cond_futex: +	movl	%eax, %esi + +	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 << clock_bits), 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 << clock_bits) - 1), %eax +	jne	25f + +	addl	$cond_nwaiters, %ebx +	movl	$SYS_futex, %eax +	movl	$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 + +	/* Remove cancellation handler.  */ +11:	movl	24+FRAME_SIZE(%esp), %eax +	call	__pthread_mutex_cond_lock +	addl	$FRAME_SIZE, %esp +.Laddl: + +	/* 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 +.Lpop_ebx: +	popl	%esi +.Lpop_esi: +	popl	%edi +.Lpop_edi: +	popl	%ebp +.Lpop_ebp: + +	ret + +	/* Initial locking failed.  */ +1: +.LSbl1: +#if cond_lock == 0 +	movl	%ebx, %ecx +#else +	leal	cond_lock(%ebx), %ecx +#endif +	call	__lll_mutex_lock_wait +	jmp	2b + +	/* Unlock in loop requires wakeup.  */ +3: +.LSbl2: +#if cond_lock == 0 +	movl	%ebx, %eax +#else +	leal	cond_lock(%ebx), %eax +#endif +	call	__lll_mutex_unlock_wake +	jmp	4b + +	/* Locking in loop failed.  */ +5: +#if cond_lock == 0 +	movl	%ebx, %ecx +#else +	leal	cond_lock(%ebx), %ecx +#endif +	call	__lll_mutex_lock_wait +	jmp	6b + +	/* Unlock after loop requires wakeup.  */ +10: +#if cond_lock == 0 +	movl	%ebx, %eax +#else +	leal	cond_lock(%ebx), %eax +#endif +	call	__lll_mutex_unlock_wake +	jmp	11b + +	/* The initial unlocking of the mutex failed.  */ +16: +.LSbl3: +	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 +	call	__lll_mutex_unlock_wake + +	movl	%esi, %eax +	jmp	18b + +#if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS +	/* clock_gettime not available.  */ +.LSbl4: +19:	leal	4(%esp), %ebx +	xorl	%ecx, %ecx +	movl	$SYS_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 +.LSbl5: +	.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, %ecx +#else +	leal	cond_lock(%ebx), %ecx +#endif +	call	__lll_mutex_lock_wait + +1:	movl	broadcast_seq(%ebx), %eax +	cmpl	20(%esp), %eax +	jne	3f + +	addl	$1, wakeup_seq(%ebx) +	adcl	$0, wakeup_seq+4(%ebx) + +	addl	$1, cond_futex(%ebx) + +	addl	$1, woken_seq(%ebx) +	adcl	$0, woken_seq+4(%ebx) + +3:	subl	$(1 << clock_bits), 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 << clock_bits) - 1), %eax +	jne	4f + +	addl	$cond_nwaiters, %ebx +	movl	$SYS_futex, %eax +	movl	$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 +	call	__lll_mutex_unlock_wake + +	/* Wake up all waiters to make sure no signal gets lost.  */ +2:	testl	%edi, %edi +	jnz	5f +	addl	$cond_futex, %ebx +	movl	$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: +	.size	__condvar_tw_cleanup, .-__condvar_tw_cleanup 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..377a7340f --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S @@ -0,0 +1,357 @@ +/* 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 <sysdep.h> +#include <lowlevelcond.h> +#include <tcb-offsets.h> + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + + +	.text + +/* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)  */ +	.globl	__pthread_cond_wait +	.type	__pthread_cond_wait, @function +	.align	16 +__pthread_cond_wait: +.LSTARTCODE: + +	pushl	%edi +.Lpush_edi: +	pushl	%esi +.Lpush_esi: +	pushl	%ebx +.Lpush_ebx: + +	xorl	%esi, %esi +	movl	16(%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	20(%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 << clock_bits), cond_nwaiters(%ebx) + +#define FRAME_SIZE 16 +	subl	$FRAME_SIZE, %esp +.Lsubl: + +	/* 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) + +8:	movl	cond_futex(%ebx), %edi + +	/* 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) + +	movl	%esi, %ecx	/* movl $FUTEX_WAIT, %ecx */ +	movl	%edi, %edx +	addl	$cond_futex, %ebx +.Ladd_cond_futex: +	movl	$SYS_futex, %eax +	ENTER_KERNEL +	subl	$cond_futex, %ebx +.Lsub_cond_futex: + +	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 << clock_bits), 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 << clock_bits) - 1), %eax +	jne	17f + +	addl	$cond_nwaiters, %ebx +	movl	$SYS_futex, %eax +	movl	$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 + +11:	movl	20+FRAME_SIZE(%esp), %eax +	call	__pthread_mutex_cond_lock +	addl	$FRAME_SIZE, %esp +.Laddl: + +14:	popl	%ebx +.Lpop_ebx: +	popl	%esi +.Lpop_esi: +	popl	%edi +.Lpop_edi: + +	/* We return the result of the mutex_lock operation.  */ +	ret + +	/* Initial locking failed.  */ +1: +.LSbl1: +#if cond_lock == 0 +	movl	%ebx, %ecx +#else +	leal	cond_lock(%ebx), %ecx +#endif +	call	__lll_mutex_lock_wait +	jmp	2b + +	/* Unlock in loop requires waekup.  */ +3: +.LSbl2: +#if cond_lock == 0 +	movl	%ebx, %eax +#else +	leal	cond_lock(%ebx), %eax +#endif +	call	__lll_mutex_unlock_wake +	jmp	4b + +	/* Locking in loop failed.  */ +5: +#if cond_lock == 0 +	movl	%ebx, %ecx +#else +	leal	cond_lock(%ebx), %ecx +#endif +	call	__lll_mutex_lock_wait +	jmp	6b + +	/* Unlock after loop requires wakeup.  */ +10: +#if cond_lock == 0 +	movl	%ebx, %eax +#else +	leal	cond_lock(%ebx), %eax +#endif +	call	__lll_mutex_unlock_wake +	jmp	11b + +	/* The initial unlocking of the mutex failed.  */ +12: +.LSbl3: +	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 +	call	__lll_mutex_unlock_wake + +	movl	%esi, %eax +	jmp	14b +	.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, %ecx +#else +	leal	cond_lock(%ebx), %ecx +#endif +	call	__lll_mutex_lock_wait + +1:	movl	broadcast_seq(%ebx), %eax +	cmpl	12(%esp), %eax +	jne	3f + +	addl	$1, wakeup_seq(%ebx) +	adcl	$0, wakeup_seq+4(%ebx) + +	addl	$1, cond_futex(%ebx) + +	addl	$1, woken_seq(%ebx) +	adcl	$0, woken_seq+4(%ebx) + +3:	subl	$(1 << clock_bits), 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 << clock_bits) - 1), %eax +	jne	4f + +	addl	$cond_nwaiters, %ebx +	movl	$SYS_futex, %eax +	movl	$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 +	call	__lll_mutex_unlock_wake + +	/* Wake up all waiters to make sure no signal gets lost.  */ +2:	testl	%edi, %edi +	jnz	5f +	addl	$cond_futex, %ebx +	movl	$FUTEX_WAKE, %ecx +	movl	$SYS_futex, %eax +	movl	$0x7fffffff, %edx +	ENTER_KERNEL + +5:	movl	20+FRAME_SIZE(%esp), %eax +	call	__pthread_mutex_cond_lock + +	movl	%esi, (%esp) +.LcallUR: +	call	_Unwind_Resume +	hlt +.LENDCODE: +	.size	__condvar_w_cleanup, .-__condvar_w_cleanup 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..aec79f07e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S @@ -0,0 +1,175 @@ +/* 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 <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> + + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + +	.text + +	.globl	__pthread_rwlock_rdlock +	.type	__pthread_rwlock_rdlock,@function +	.align	16 +__pthread_rwlock_rdlock: +	pushl	%esi +	pushl	%ebx + +	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 +	cmpl	$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:	addl	$READERS_WAKEUP, %ebx +	movl	%esi, %ecx	/* movl $FUTEX_WAIT, %ecx */ +	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	%ecx, %ecx +	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	%ecx, %eax +	popl	%ebx +	popl	%esi +	ret + +1: +#if MUTEX == 0 +	movl	%ebx, %ecx +#else +	leal	MUTEX(%ebx), %ecx +#endif +	call	__lll_mutex_lock_wait +	jmp	2b + +14:	cmpl	%gs:TID, %eax +	jne	3b +	/* Deadlock detected.  */ +	movl	$EDEADLK, %ecx +	jmp	9b + +6: +#if MUTEX == 0 +	movl	%ebx, %eax +#else +	leal	MUTEX(%ebx), %eax +#endif +	call	__lll_mutex_unlock_wake +	jmp	7b + +	/* Overflow.  */ +8:	subl	$1, NR_READERS(%ebx) +	movl	$EAGAIN, %ecx +	jmp	9b + +	/* Overflow.  */ +4:	subl	$1, READERS_QUEUED(%ebx) +	movl	$EAGAIN, %ecx +	jmp	9b + +10: +#if MUTEX == 0 +	movl	%ebx, %eax +#else +	leal	MUTEX(%ebx), %eax +#endif +	call	__lll_mutex_unlock_wake +	jmp	11b + +12: +#if MUTEX == 0 +	movl	%ebx, %ecx +#else +	leal	MUTEX(%ebx), %ecx +#endif +	call	__lll_mutex_lock_wait +	jmp	13b +	.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..3717d7ef5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S @@ -0,0 +1,214 @@ +/* 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 <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> + + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + +	.text + +	.globl	pthread_rwlock_timedrdlock +	.type	pthread_rwlock_timedrdlock,@function +	.align	16 +pthread_rwlock_timedrdlock: +	pushl	%esi +	pushl	%edi +	pushl	%ebx +	pushl	%ebp +	subl	$8, %esp + +	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 +	cmpl	$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	$SYS_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 +	xorl	%ecx, %ecx	/* movl $FUTEX_WAIT, %ecx */ +	movl	%esp, %esi +	leal	READERS_WAKEUP(%ebp), %ebx +	movl	$SYS_futex, %eax +	ENTER_KERNEL +	movl	%eax, %ecx +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, %ecx +	jne	2b + +18:	movl	$ETIMEDOUT, %ecx +	jmp	9f + + +5:	xorl	%ecx, %ecx +	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	%ecx, %eax + +	addl	$8, %esp +	popl	%ebp +	popl	%ebx +	popl	%edi +	popl	%esi +	ret + +1: +#if MUTEX == 0 +	movl	%ebp, %ecx +#else +	leal	MUTEX(%ebp), %ecx +#endif +	call	__lll_mutex_lock_wait +	jmp	2b + +14:	cmpl	%gs:TID, %eax +	jne	3b +	movl	$EDEADLK, %ecx +	jmp	9b + +6: +#if MUTEX == 0 +	movl	%ebp, %eax +#else +	leal	MUTEX(%ebp), %eax +#endif +	call	__lll_mutex_unlock_wake +	jmp	7b + +	/* Overflow.  */ +8:	subl	$1, NR_READERS(%ebp) +	movl	$EAGAIN, %ecx +	jmp	9b + +	/* Overflow.  */ +4:	subl	$1, READERS_QUEUED(%ebp) +	movl	$EAGAIN, %ecx +	jmp	9b + +10: +#if MUTEX == 0 +	movl	%ebp, %eax +#else +	leal	MUTEX(%ebp), %eax +#endif +	call	__lll_mutex_unlock_wake +	jmp	11b + +12: +#if MUTEX == 0 +	movl	%ebp, %ecx +#else +	leal	MUTEX(%ebp), %ecx +#endif +	call	__lll_mutex_lock_wait +	jmp	13b + +16:	movl	$-ETIMEDOUT, %ecx +	jmp	17b + +19:	movl	$EINVAL, %ecx +	jmp	9b +	.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..09c9e30ca --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S @@ -0,0 +1,207 @@ +/* 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 <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> + + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + +	.text + +	.globl	pthread_rwlock_timedwrlock +	.type	pthread_rwlock_timedwrlock,@function +	.align	16 +pthread_rwlock_timedwrlock: +	pushl	%esi +	pushl	%edi +	pushl	%ebx +	pushl	%ebp +	subl	$8, %esp + +	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	$SYS_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 +	xorl	%ecx, %ecx	/* movl $FUTEX_WAIT, %ecx */ +	movl	%esp, %esi +	leal	WRITERS_WAKEUP(%ebp), %ebx +	movl	$SYS_futex, %eax +	ENTER_KERNEL +	movl	%eax, %ecx +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, %ecx +	jne	2b + +18:	movl	$ETIMEDOUT, %ecx +	jmp	9f + + +5:	xorl	%ecx, %ecx +	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	%ecx, %eax + +	addl	$8, %esp +	popl	%ebp +	popl	%ebx +	popl	%edi +	popl	%esi +	ret + +1: +#if MUTEX == 0 +	movl	%ebp, %ecx +#else +	leal	MUTEX(%ebp), %ecx +#endif +	call	__lll_mutex_lock_wait +	jmp	2b + +14:	cmpl	%gs:TID, %eax +	jne	3b +20:	movl	$EDEADLK, %ecx +	jmp	9b + +6: +#if MUTEX == 0 +	movl	%ebp, %eax +#else +	leal	MUTEX(%ebp), %eax +#endif +	call	__lll_mutex_unlock_wake +	jmp	7b + +	/* Overflow.  */ +4:	subl	$1, WRITERS_QUEUED(%ebp) +	movl	$EAGAIN, %ecx +	jmp	9b + +10: +#if MUTEX == 0 +	movl	%ebp, %eax +#else +	leal	MUTEX(%ebp), %eax +#endif +	call	__lll_mutex_unlock_wake +	jmp	11b + +12: +#if MUTEX == 0 +	movl	%ebp, %ecx +#else +	leal	MUTEX(%ebp), %ecx +#endif +	call	__lll_mutex_lock_wait +	jmp	13b + +16:	movl	$-ETIMEDOUT, %ecx +	jmp	17b + +19:	movl	$EINVAL, %ecx +	jmp	9b +	.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..597c82fa8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S @@ -0,0 +1,140 @@ +/* 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 <sysdep.h> +#include <lowlevelrwlock.h> + + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + +	.text + +	.globl	__pthread_rwlock_unlock +	.type	__pthread_rwlock_unlock,@function +	.align	16 +__pthread_rwlock_unlock: +	pushl	%ebx +	pushl	%edi + +	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, %ecx +	leal	WRITERS_WAKEUP(%edi), %ebx +	movl	%ecx, %edx +	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:	movl	$SYS_futex, %eax +	ENTER_KERNEL + +	xorl	%eax, %eax +	popl	%edi +	popl	%ebx +	ret + +	.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, %ecx +#else +	leal	MUTEX(%edx), %ecx +#endif +	call	__lll_mutex_lock_wait +	jmp	2b + +3: +#if MUTEX == 0 +	movl	%edi, %eax +#else +	leal	MUTEX(%edx), %eax +#endif +	call	__lll_mutex_unlock_wake +	jmp	4b + +7: +#if MUTEX == 0 +	movl	%edi, %eax +#else +	leal	MUTEX(%edx), %eax +#endif +	call	__lll_mutex_unlock_wake +	jmp	8b + +	.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..bb384a267 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S @@ -0,0 +1,165 @@ +/* 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 <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + +	.text + +	.globl	__pthread_rwlock_wrlock +	.type	__pthread_rwlock_wrlock,@function +	.align	16 +__pthread_rwlock_wrlock: +	pushl	%esi +	pushl	%ebx + +	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:	addl	$WRITERS_WAKEUP, %ebx +	movl	%esi, %ecx	/* movl $FUTEX_WAIT, %ecx */ +	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	%ecx, %ecx +	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	%ecx, %eax +	popl	%ebx +	popl	%esi +	ret + +1: +#if MUTEX == 0 +	movl	%ebx, %ecx +#else +	leal	MUTEX(%ebx), %ecx +#endif +	call	__lll_mutex_lock_wait +	jmp	2b + +14:	cmpl	%gs:TID	, %eax +	jne	3b +	movl	$EDEADLK, %ecx +	jmp	9b + +6: +#if MUTEX == 0 +	movl	%ebx, %eax +#else +	leal	MUTEX(%ebx), %eax +#endif +	call	__lll_mutex_unlock_wake +	jmp	7b + +4:	subl	$1, WRITERS_QUEUED(%ebx) +	movl	$EAGAIN, %ecx +	jmp	9b + +10: +#if MUTEX == 0 +	movl	%ebx, %eax +#else +	leal	MUTEX(%ebx), %eax +#endif +	call	__lll_mutex_unlock_wake +	jmp	11b + +12: +#if MUTEX == 0 +	movl	%ebx, %ecx +#else +	leal	MUTEX(%ebx), %ecx +#endif +	call	__lll_mutex_lock_wait +	jmp	13b +	.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..a0dc39c8f --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_post.S @@ -0,0 +1,96 @@ +/* Copyright (C) 2002, 2003, 2005 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 <tls.h> + +#ifndef UP +# define LOCK lock +#else +# define +#endif + +#define FUTEX_WAKE		1 + + +	.text + +	.globl	__new_sem_post +	.type	__new_sem_post,@function +	.align	16 +__new_sem_post: +	pushl	%ebx + +	movl	8(%esp), %ebx +	movl	$1, %edx +	LOCK +	xaddl	%edx, (%ebx) + +	movl	$SYS_futex, %eax +	movl	$FUTEX_WAKE, %ecx +	addl	$1, %edx +	ENTER_KERNEL + +	testl	%eax, %eax +	js	1f + +	xorl	%eax, %eax +	popl	%ebx +	ret + +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 +	.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..972b49fac --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S @@ -0,0 +1,193 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 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 <tcb-offsets.h> + +#ifndef UP +# define LOCK lock +#else +# define +#endif + +#define FUTEX_WAKE		1 + + +	.text + +	.globl	sem_timedwait +	.type	sem_timedwait,@function +	.align	16 +	cfi_startproc +sem_timedwait: +	/* First check for cancellation.  */ +	movl	%gs:CANCELHANDLING, %eax +	andl	$0xfffffff9, %eax +	cmpl	$8, %eax +	je	10f + +	movl	4(%esp), %ecx + +	movl	(%ecx), %eax +2:	testl	%eax, %eax +	je,pn	1f + +	leal	-1(%eax), %edx +	LOCK +	cmpxchgl %edx, (%ecx) +	jne,pn	2b + +	xorl	%eax, %eax +	ret + +	/* Check whether the timeout value is valid.  */ +1:	pushl	%esi +	cfi_adjust_cfa_offset(4) +	pushl	%edi +	cfi_adjust_cfa_offset(4) +	pushl	%ebx +	cfi_adjust_cfa_offset(4) +	subl	$12, %esp +	cfi_adjust_cfa_offset(12) + +	movl	32(%esp), %edi +	cfi_offset(7, -12)		/* %edi */ + +	/* Check for invalid nanosecond field.  */ +	cmpl	$1000000000, 4(%edi) +	movl	$EINVAL, %esi +	cfi_offset(6, -8)		/* %esi */ +	jae	6f + +	cfi_offset(3, -16)		/* %ebx */ +7:	call	__pthread_enable_asynccancel +	movl	%eax, 8(%esp) + +	xorl	%ecx, %ecx +	movl	%esp, %ebx +	movl	%ecx, %edx +	movl	$SYS_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) +	movl	28(%esp), %ebx +	xorl	%ecx, %ecx +	movl	%esp, %esi +	movl	$SYS_futex, %eax +	xorl	%edx, %edx +	ENTER_KERNEL +	movl	%eax, %esi + +	movl	8(%esp), %eax +	call	__pthread_disable_asynccancel + +	testl	%esi, %esi +	je,pt	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,pn	8b + +	addl	$12, %esp +	cfi_adjust_cfa_offset(-12) +	xorl	%eax, %eax +	popl	%ebx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(3) +	popl	%edi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(7) +	popl	%esi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(6) +	ret + +	cfi_adjust_cfa_offset(24) +	cfi_offset(6, -8)		/* %esi */ +	cfi_offset(7, -12)	 	/* %edi */ +	cfi_offset(3, -16)		/* %ebx */ +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 + +	addl	$12, %esp +	cfi_adjust_cfa_offset(-12) +	orl	$-1, %eax +	popl	%ebx +	cfi_adjust_cfa_offset(-4) +	cfi_restore(3) +	popl	%edi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(7) +	popl	%esi +	cfi_adjust_cfa_offset(-4) +	cfi_restore(6) +	ret + +10:	/* Canceled.  */ +	movl	$0xffffffff, %gs:RESULT +	LOCK +	orl	$0x10, %gs:CANCELHANDLING +	movl	%gs:CLEANUP_JMP_BUF, %eax +	jmp	HIDDEN_JUMPTARGET (__pthread_unwind) +	cfi_endproc +	.size	sem_timedwait,.-sem_timedwait 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..7db64820f --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_trywait.S @@ -0,0 +1,85 @@ +/* Copyright (C) 2002, 2003, 2005 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 <tls.h> + +#ifndef UP +# define LOCK lock +#else +# define +#endif + +	.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,pn	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..c3e6cbce6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_wait.S @@ -0,0 +1,134 @@ +/* Copyright (C) 2002, 2003, 2005 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 <tcb-offsets.h> +#include <tls.h> + +#ifndef UP +# define LOCK lock +#else +# define +#endif + +#define FUTEX_WAKE		1 + + +	.text + +	.globl	__new_sem_wait +	.type	__new_sem_wait,@function +	.align	16 +	cfi_startproc +__new_sem_wait: +	/* First check for cancellation.  */ +	movl	%gs:CANCELHANDLING, %eax +	andl	$0xfffffff9, %eax +	cmpl	$8, %eax +	je	5f + +	pushl	%ebx +	cfi_adjust_cfa_offset(4) +	pushl	%esi +	cfi_adjust_cfa_offset(4) +	subl	$4, %esp +	cfi_adjust_cfa_offset(4) + +	movl	16(%esp), %ebx +	cfi_offset(3, -8)		/* %ebx */ + +	cfi_offset(6, -12)		/* %esi */ +3:	movl	(%ebx), %eax +2:	testl	%eax, %eax +	je,pn	1f + +	leal	-1(%eax), %edx +	LOCK +	cmpxchgl %edx, (%ebx) +	jne,pn	2b +	xorl	%eax, %eax + +	movl	4(%esp), %esi +	cfi_restore(6) +	movl	8(%esp), %ebx +	cfi_restore(3) +	addl	$12, %esp +	cfi_adjust_cfa_offset(-12) +	ret + +	cfi_adjust_cfa_offset(8) +	cfi_offset(3, -8)		/* %ebx */ +	cfi_offset(6, -12)		/* %esi */ +1:	call	__pthread_enable_asynccancel +	movl	%eax, (%esp) + +	xorl	%esi, %esi +	movl	$SYS_futex, %eax +	movl	%esi, %ecx +	movl	%esi, %edx +	ENTER_KERNEL +	movl	%eax, %esi + +	movl	(%esp), %eax +	call	__pthread_disable_asynccancel + +	testl	%esi, %esi +	je	3b +	cmpl	$-EWOULDBLOCK, %esi +	je	3b +	negl	%esi +#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 +	orl	$-1, %eax +	movl	4(%esp), %esi +	cfi_restore(6) +	movl	8(%esp), %ebx +	cfi_restore(3) +	addl	$12, %esp +	cfi_adjust_cfa_offset(-12) +	ret + +5:	/* Canceled.  */ +	movl	$0xffffffff, %gs:RESULT +	LOCK +	orl	$0x10, %gs:CANCELHANDLING +	movl	%gs:CLEANUP_JMP_BUF, %eax +	jmp	HIDDEN_JUMPTARGET (__pthread_unwind) +	cfi_endproc +	.size	__new_sem_wait,.-__new_sem_wait +weak_alias(__new_sem_wait, sem_wait) 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/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/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..97f3b09e2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h @@ -0,0 +1,365 @@ +/* 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.  */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H	1 + +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> +#include <atomic.h> +#include <sysdep.h> + +/* We have a separate internal lock implementation which is not tied +   to binary compatibility.  */ + +/* Type for lock object.  */ +typedef int lll_lock_t; + +/* Initializers for lock.  */ +#define LLL_LOCK_INITIALIZER		(0) +#define LLL_LOCK_INITIALIZER_LOCKED	(1) + +#include <tls.h> + +#ifndef LOCK_INSTR +# define LOCK_INSTR "lock;" +#endif + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + + +/* Initializer for compatibility lock.  */ +#define LLL_MUTEX_LOCK_INITIALIZER		(0) +#define LLL_MUTEX_LOCK_INITIALIZER_LOCKED	(1) +#define LLL_MUTEX_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 + +#define LLL_ENTER_KERNEL	"int $0x80\n\t" + +/* Delay in spinlock loop.  */ +#define BUSY_WAIT_NOP          __asm__ ("rep; nop") + +#define lll_futex_wait(futex, val) \ +  lll_futex_timed_wait (futex, val, NULL) + +#define lll_futex_timed_wait(futex, val, timeout) \ +  ({									      \ +    int __ret;							      \ +    register __typeof (val) _val __asm__ ("edx") = (val);		      \ +    __asm__ __volatile (LLL_EBX_LOAD					      \ +		      LLL_ENTER_KERNEL					      \ +		      LLL_EBX_LOAD					      \ +		      : "=a" (__ret)					      \ +		      : "0" (SYS_futex), LLL_EBX_REG (futex), "S" (timeout),  \ +			"c" (FUTEX_WAIT), "d" (_val),			      \ +			"i" (offsetof (tcbhead_t, sysinfo)));		      \ +   __ret; }) + + +#define lll_futex_wake(futex, nr) \ +  ({									      \ +    int __ret;							      \ +    register __typeof (nr) _nr __asm__ ("edx") = (nr);			      \ +    __asm__ __volatile (LLL_EBX_LOAD					      \ +		      LLL_ENTER_KERNEL					      \ +		      LLL_EBX_LOAD					      \ +		      : "=a" (__ret)					      \ +		      : "0" (SYS_futex), LLL_EBX_REG (futex),		      \ +			"c" (FUTEX_WAKE), "d" (_nr),			      \ +			"i" (0) /* phony, to align next arg's number */,      \ +			"i" (offsetof (tcbhead_t, sysinfo)));		      \ +   __ret; }) + + +/* Does not preserve %eax and %ecx.  */ +extern int __lll_mutex_lock_wait (int val, int *__futex) +     __attribute ((regparm (2))) attribute_hidden; +/* Does not preserve %eax, %ecx, and %edx.  */ +extern int __lll_mutex_timedlock_wait (int val, int *__futex, +				       const struct timespec *abstime) +     __attribute ((regparm (3))) attribute_hidden; +/* Preserves all registers but %eax.  */ +extern int __lll_mutex_unlock_wake (int *__futex) +     __attribute ((regparm (1))) attribute_hidden; + + +/* NB: in the lll_mutex_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.  */ +#define lll_mutex_trylock(futex) \ +  ({ int ret;								      \ +     __asm__ __volatile (LOCK_INSTR "cmpxchgl %2, %1"			      \ +		       : "=a" (ret), "=m" (futex)			      \ +		       : "r" (LLL_MUTEX_LOCK_INITIALIZER_LOCKED), "m" (futex),\ +			 "0" (LLL_MUTEX_LOCK_INITIALIZER)		      \ +		       : "memory");					      \ +     ret; }) + + +#define lll_mutex_cond_trylock(futex) \ +  ({ int ret;								      \ +     __asm__ __volatile (LOCK_INSTR "cmpxchgl %2, %1"			      \ +		       : "=a" (ret), "=m" (futex)			      \ +		       : "r" (LLL_MUTEX_LOCK_INITIALIZER_WAITERS),	      \ +			  "m" (futex), "0" (LLL_MUTEX_LOCK_INITIALIZER)	      \ +		       : "memory");					      \ +     ret; }) + + +#define lll_mutex_lock(futex) \ +  (void) ({ int ignore1, ignore2;					      \ +	    __asm__ __volatile (LOCK_INSTR "cmpxchgl %1, %2\n\t"	      \ +			      "jnz _L_mutex_lock_%=\n\t"		      \ +			      ".subsection 1\n\t"			      \ +			      ".type _L_mutex_lock_%=,@function\n"	      \ +			      "_L_mutex_lock_%=:\n\t"			      \ +			      "leal %2, %%ecx\n\t"			      \ +			      "call __lll_mutex_lock_wait\n\t"		      \ +			      "jmp 1f\n\t"				      \ +			      ".size _L_mutex_lock_%=,.-_L_mutex_lock_%=\n"   \ +			      ".previous\n"				      \ +			      "1:"					      \ +			      : "=a" (ignore1), "=c" (ignore2), "=m" (futex)  \ +			      : "0" (0), "1" (1), "m" (futex)		      \ +			      : "memory"); }) + + +/* Special version of lll_mutex_lock which causes the unlock function to +   always wakeup waiters.  */ +#define lll_mutex_cond_lock(futex) \ +  (void) ({ int ignore1, ignore2;					      \ +	    __asm__ __volatile (LOCK_INSTR "cmpxchgl %1, %2\n\t"	      \ +			      "jnz _L_mutex_cond_lock_%=\n\t"		      \ +			      ".subsection 1\n\t"			      \ +			      ".type _L_mutex_cond_lock_%=,@function\n"	      \ +			      "_L_mutex_cond_lock_%=:\n\t"		      \ +			      "leal %2, %%ecx\n\t"			      \ +			      "call __lll_mutex_lock_wait\n\t"		      \ +			      "jmp 1f\n\t"				      \ +			      ".size _L_mutex_cond_lock_%=,.-_L_mutex_cond_lock_%=\n"   \ +			      ".previous\n"				      \ +			      "1:"					      \ +			      : "=a" (ignore1), "=c" (ignore2), "=m" (futex)  \ +			      : "0" (0), "1" (2), "m" (futex)		      \ +			      : "memory"); }) + + +#define lll_mutex_timedlock(futex, timeout) \ +  ({ int _result, ignore1, ignore2;					      \ +     __asm__ __volatile (LOCK_INSTR "cmpxchgl %1, %3\n\t"		      \ +		       "jnz _L_mutex_timedlock_%=\n\t"			      \ +		       ".subsection 1\n\t"				      \ +		       ".type _L_mutex_timedlock_%=,@function\n"	      \ +		       "_L_mutex_timedlock_%=:\n\t"			      \ +		       "leal %3, %%ecx\n\t"				      \ +		       "movl %7, %%edx\n\t"				      \ +		       "call __lll_mutex_timedlock_wait\n\t"		      \ +		       "jmp 1f\n\t"					      \ +		       ".size _L_mutex_timedlock_%=,.-_L_mutex_timedlock_%=\n"\ +		       ".previous\n"					      \ +		       "1:"						      \ +		       : "=a" (_result), "=c" (ignore1), "=&d" (ignore2),      \ +			 "=m" (futex)					      \ +		       : "0" (0), "1" (1), "m" (futex), "m" (timeout)	      \ +		       : "memory");					      \ +     _result; }) + + +#define lll_mutex_unlock(futex) \ +  (void) ({ int ignore;							      \ +            __asm__ __volatile (LOCK_INSTR "subl $1,%0\n\t"		      \ +			      "jne _L_mutex_unlock_%=\n\t"		      \ +			      ".subsection 1\n\t"			      \ +			      ".type _L_mutex_unlock_%=,@function\n"	      \ +			      "_L_mutex_unlock_%=:\n\t"			      \ +			      "leal %0, %%eax\n\t"			      \ +			      "call __lll_mutex_unlock_wake\n\t"	      \ +			      "jmp 1f\n\t"				      \ +			      ".size _L_mutex_unlock_%=,.-_L_mutex_unlock_%=\n" \ +			      ".previous\n"				      \ +			      "1:"					      \ +			      : "=m" (futex), "=&a" (ignore)		      \ +			      : "m" (futex)				      \ +			      : "memory"); }) + + +#define lll_mutex_islocked(futex) \ +  (futex != 0) + + +extern int __lll_lock_wait (int val, int *__futex) +     __attribute ((regparm (2))) attribute_hidden; +extern int __lll_unlock_wake (int *__futex) +     __attribute ((regparm (1))) attribute_hidden; +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + + +/* The states of a lock are: +    0  -  untaken +    1  -  taken by one user +    2  -  taken by more users */ + + +#if defined NOT_IN_libc +# define lll_trylock(futex) lll_mutex_trylock (futex) +# define lll_lock(futex) lll_mutex_lock (futex) +# define lll_unlock(futex) lll_mutex_unlock (futex) +#else +/* Special versions of the macros for use in libc itself.  They avoid +   the lock prefix when the thread library is not used. */ + + + +# define lll_trylock(futex) \ +  ({ unsigned char ret;							      \ +     __asm__ __volatile ("cmpl $0, %%gs:%P5\n\t"			      \ +		       "je,pt 0f\n\t"					      \ +		       "lock\n"						      \ +		       "0:\tcmpxchgl %2, %1; setne %0"			      \ +		       : "=a" (ret), "=m" (futex)			      \ +		       : "r" (LLL_MUTEX_LOCK_INITIALIZER_LOCKED), "m" (futex),\ +			 "0" (LLL_MUTEX_LOCK_INITIALIZER),		      \ +		         "i" (offsetof (tcbhead_t, multiple_threads))	      \ +		       : "memory");					      \ +     ret; }) + + +# define lll_lock(futex) \ +  (void) ({ int ignore1, ignore2;					      \ +	    __asm__ __volatile ("cmpl $0, %%gs:%P6\n\t"			      \ +			      "je,pt 0f\n\t"				      \ +			      "lock\n"					      \ +			      "0:\tcmpxchgl %1, %2\n\t"			      \ +			      "jnz _L_mutex_lock_%=\n\t"		      \ +			      ".subsection 1\n\t"			      \ +			      ".type _L_mutex_lock_%=,@function\n"	      \ +			      "_L_mutex_lock_%=:\n\t"			      \ +			      "leal %2, %%ecx\n\t"			      \ +			      "call __lll_mutex_lock_wait\n\t"		      \ +			      "jmp 1f\n\t"				      \ +			      ".size _L_mutex_lock_%=,.-_L_mutex_lock_%=\n"   \ +			      ".previous\n"				      \ +			      "1:"					      \ +			      : "=a" (ignore1), "=c" (ignore2), "=m" (futex)  \ +			      : "0" (0), "1" (1), "m" (futex),		      \ +		                "i" (offsetof (tcbhead_t, multiple_threads))  \ +			      : "memory"); }) + + +# define lll_unlock(futex) \ +  (void) ({ int ignore;							      \ +            __asm__ __volatile ("cmpl $0, %%gs:%P3\n\t"			      \ +			      "je,pt 0f\n\t"				      \ +			      "lock\n"					      \ +			      "0:\tsubl $1,%0\n\t"		      \ +			      "jne _L_mutex_unlock_%=\n\t"		      \ +			      ".subsection 1\n\t"			      \ +			      ".type _L_mutex_unlock_%=,@function\n"	      \ +			      "_L_mutex_unlock_%=:\n\t"			      \ +			      "leal %0, %%eax\n\t"			      \ +			      "call __lll_mutex_unlock_wake\n\t"	      \ +			      "jmp 1f\n\t"				      \ +			      ".size _L_mutex_unlock_%=,.-_L_mutex_unlock_%=\n" \ +			      ".previous\n"				      \ +			      "1:"					      \ +			      : "=m" (futex), "=&a" (ignore)		      \ +			      : "m" (futex),				      \ +				"i" (offsetof (tcbhead_t, multiple_threads))  \ +			      : "memory"); }) +#endif + + +#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) \ +  ({									      \ +    int __ret;								      \ +    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,pn 1b\n\t"					      \ +			LLL_EBX_LOAD					      \ +			: "=&a" (__ret)				              \ +			: "i" (SYS_futex), LLL_EBX_REG (&tid), "S" (0),	      \ +			  "c" (FUTEX_WAIT), "d" (_tid),			      \ +			  "i" (offsetof (tcbhead_t, sysinfo)));		      \ +   __ret; }) + +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; }) + + +/* Conditional variable handling.  */ + +extern void __lll_cond_wait (pthread_cond_t *cond) +     __attribute ((regparm (1))) attribute_hidden; +extern int __lll_cond_timedwait (pthread_cond_t *cond, +				 const struct timespec *abstime) +     __attribute ((regparm (2))) attribute_hidden; +extern void __lll_cond_wake (pthread_cond_t *cond) +     __attribute ((regparm (1))) attribute_hidden; +extern void __lll_cond_broadcast (pthread_cond_t *cond) +     __attribute ((regparm (1))) attribute_hidden; + + +#define lll_cond_wait(cond) \ +  __lll_cond_wait (cond) +#define lll_cond_timedwait(cond, abstime) \ +  __lll_cond_timedwait (cond, abstime) +#define lll_cond_wake(cond) \ +  __lll_cond_wake (cond) +#define lll_cond_broadcast(cond) \ +  __lll_cond_broadcast (cond) + + +#endif	/* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/not-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/not-cancel.h new file mode 100644 index 000000000..5bdba3f51 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/not-cancel.h @@ -0,0 +1,82 @@ +/* Uncancelable versions of cancelable interfaces.  Linux/NPTL version. +   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 <sysdep.h> + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt +extern int __open_nocancel (const char *, int, ...) attribute_hidden; +extern int __close_nocancel (int) attribute_hidden; +extern int __read_nocancel (int, void *, size_t) attribute_hidden; +extern int __write_nocancel (int, const void *, size_t) attribute_hidden; +extern pid_t __waitpid_nocancel (pid_t, int *, int) attribute_hidden; + +libc_hidden_proto(__open_nocancel) +libc_hidden_proto(__close_nocancel) +libc_hidden_proto(__read_nocancel) +libc_hidden_proto(__write_nocancel) +libc_hidden_proto(__waitpid_nocancel) + +#else +#define __open_nocancel(name, ...) open (name, __VA_ARGS__) +#define __close_nocancel(fd) close (fd) +#define __read_nocancel(fd, buf, len) read (fd, buf, len) +#define __write_nocancel(fd, buf, len) write (fd, buf, len) +#define __waitpid_nocancel(pid, stat_loc, options) \ +  waitpid (pid, stat_loc, options) +#endif + +/* Uncancelable open.  */ +#define open_not_cancel(name, flags, mode) \ +   __open_nocancel (name, flags, mode) +#define open_not_cancel_2(name, flags) \ +   __open_nocancel (name, flags) + +/* Uncancelable close.  */ +#define close_not_cancel(fd) \ +  __close_nocancel (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) \ +  __read_nocancel (fd, buf, n) + +/* Uncancelable write.  */ +#define write_not_cancel(fd, buf, n) \ +  __write_nocancel (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) \ +  __waitpid_nocancel (pid, stat_loc, options) +#else +# define waitpid_not_cancel(pid, stat_loc, options) \ +  INLINE_SYSCALL (wait4, 4, pid, stat_loc, options, NULL) +#endif 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..939538927 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pt-vfork.S @@ -0,0 +1,36 @@ +/* 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 <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: + +#include <../../../../../../../libc/sysdeps/linux/i386/vfork.S> 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..5ab2c5856 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/pthread_once.S @@ -0,0 +1,181 @@ +/* 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 <unwindbuf.h> +#include <sysdep.h> + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + +#define FUTEX_WAKE	1 + +	.comm	__fork_generation, 4, 4 + +	.text + + +	.globl	__pthread_once +	.type	__pthread_once,@function +	.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.  */ +	movl	%esi, %ecx		/* movl $FUTEX_WAIT, %ecx */ +	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 +	movl	$FUTEX_WAKE, %ecx +	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 +	movl	$FUTEX_WAKE, %ecx +	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..2c0cbe99a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/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/i386/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h new file mode 100644 index 000000000..f32c5bd20 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h @@ -0,0 +1,139 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 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 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); + +# 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 + +# 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 diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/i386/sysdep.h b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/sysdep.h new file mode 100644 index 000000000..674d5c699 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/sysdep.h @@ -0,0 +1,336 @@ +/* Copyright (C) 1992,1993,1995-2000,2002-2006,2007 +	Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper, <drepper@gnu.org>, August 1995. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License 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 _LINUX_I386_SYSDEP_H +#define _LINUX_I386_SYSDEP_H 1 + +#include <sys/syscall.h> +#include <sysdeps/i386/sysdep.h> + +#ifndef offsetof +# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +/* For Linux we can use the system call table in the header file +	/usr/include/asm/unistd.h +   of the kernel.  But these symbols do not follow the SYS_* syntax +   so we have to redefine the `SYS_ify' macro here.  */ +#undef SYS_ify +#define SYS_ify(syscall_name)	__NR_##syscall_name + +#if defined USE_DL_SYSINFO \ +    && (!defined NOT_IN_libc || defined IS_IN_libpthread) +# define I386_USE_SYSENTER	1 +#else +# undef I386_USE_SYSENTER +#endif + +#ifdef __ASSEMBLER__ + +/* Linux uses a negative return value to indicate syscall errors, +   unlike most Unices, which use the condition codes' carry flag. + +   Since version 2.1 the return value of a system call might be +   negative even if the call succeeded.  E.g., the `lseek' system call +   might return a large offset.  Therefore we must not anymore test +   for < 0, but test for a real error by making sure the value in %eax +   is a real error number.  Linus said he will make sure the no syscall +   returns a value in -1 .. -4095 as a valid result so we can savely +   test with -4095.  */ + +/* We don't want the label for the error handle to be global when we define +   it here.  */ +#ifdef __PIC__ +# define SYSCALL_ERROR_LABEL 0f +#else +# define SYSCALL_ERROR_LABEL syscall_error +#endif + +#undef	PSEUDO +#define	PSEUDO(name, syscall_name, args)				      \ +  .text;								      \ +  ENTRY (name)								      \ +    DO_CALL (syscall_name, args);					      \ +    cmpl $-4095, %eax;							      \ +    jae SYSCALL_ERROR_LABEL;						      \ +  L(pseudo_end): + +#undef	PSEUDO_END +#define	PSEUDO_END(name)						      \ +  SYSCALL_ERROR_HANDLER							      \ +  END (name) + +#undef	PSEUDO_NOERRNO +#define	PSEUDO_NOERRNO(name, syscall_name, args)			      \ +  .text;								      \ +  ENTRY (name)								      \ +    DO_CALL (syscall_name, args) + +#undef	PSEUDO_END_NOERRNO +#define	PSEUDO_END_NOERRNO(name)					      \ +  END (name) + +#define ret_NOERRNO ret + +/* The function has to return the error code.  */ +#undef	PSEUDO_ERRVAL +#define	PSEUDO_ERRVAL(name, syscall_name, args) \ +  .text;								      \ +  ENTRY (name)								      \ +    DO_CALL (syscall_name, args);					      \ +    negl %eax + +#undef	PSEUDO_END_ERRVAL +#define	PSEUDO_END_ERRVAL(name) \ +  END (name) + +#define ret_ERRVAL ret + +#ifndef __PIC__ +# define SYSCALL_ERROR_HANDLER	/* Nothing here; code in sysdep.S is used.  */ +#else + +# ifdef RTLD_PRIVATE_ERRNO +#  define SYSCALL_ERROR_HANDLER						      \ +0:SETUP_PIC_REG(cx);							      \ +  addl $_GLOBAL_OFFSET_TABLE_, %ecx;					      \ +  xorl %edx, %edx;							      \ +  subl %eax, %edx;							      \ +  movl %edx, rtld_errno@GOTOFF(%ecx);					      \ +  orl $-1, %eax;							      \ +  jmp L(pseudo_end); + +# elif defined _LIBC_REENTRANT + +#  if USE___THREAD +#   ifndef NOT_IN_libc +#    define SYSCALL_ERROR_ERRNO __libc_errno +#   else +#    define SYSCALL_ERROR_ERRNO errno +#   endif +#   define SYSCALL_ERROR_HANDLER					      \ +0:SETUP_PIC_REG (cx);							      \ +  addl $_GLOBAL_OFFSET_TABLE_, %ecx;					      \ +  movl SYSCALL_ERROR_ERRNO@GOTNTPOFF(%ecx), %ecx;			      \ +  xorl %edx, %edx;							      \ +  subl %eax, %edx;							      \ +  SYSCALL_ERROR_HANDLER_TLS_STORE (%edx, %ecx);				      \ +  orl $-1, %eax;							      \ +  jmp L(pseudo_end); +#   ifndef NO_TLS_DIRECT_SEG_REFS +#    define SYSCALL_ERROR_HANDLER_TLS_STORE(src, destoff)		      \ +  movl src, %gs:(destoff) +#   else +#    define SYSCALL_ERROR_HANDLER_TLS_STORE(src, destoff)		      \ +  addl %gs:0, destoff;							      \ +  movl src, (destoff) +#   endif +#  else +#   define SYSCALL_ERROR_HANDLER					      \ +0:pushl %ebx;								      \ +  cfi_adjust_cfa_offset (4);						      \ +  cfi_rel_offset (ebx, 0);						      \ +  SETUP_PIC_REG (bx);							      \ +  addl $_GLOBAL_OFFSET_TABLE_, %ebx;					      \ +  xorl %edx, %edx;							      \ +  subl %eax, %edx;							      \ +  pushl %edx;								      \ +  cfi_adjust_cfa_offset (4);						      \ +  call __errno_location@PLT;					              \ +  popl %ecx;								      \ +  cfi_adjust_cfa_offset (-4);						      \ +  popl %ebx;								      \ +  cfi_adjust_cfa_offset (-4);						      \ +  cfi_restore (ebx);							      \ +  movl %ecx, (%eax);							      \ +  orl $-1, %eax;							      \ +  jmp L(pseudo_end); +/* A quick note: it is assumed that the call to `__errno_location' does +   not modify the stack!  */ +#  endif +# else +/* Store (- %eax) into errno through the GOT.  */ +#  define SYSCALL_ERROR_HANDLER						      \ +0:SETUP_PIC_REG(cx);							      \ +  addl $_GLOBAL_OFFSET_TABLE_, %ecx;					      \ +  xorl %edx, %edx;							      \ +  subl %eax, %edx;							      \ +  movl errno@GOT(%ecx), %ecx;						      \ +  movl %edx, (%ecx);							      \ +  orl $-1, %eax;							      \ +  jmp L(pseudo_end); +# endif	/* _LIBC_REENTRANT */ +#endif	/* __PIC__ */ + + +/* The original calling convention for system calls on Linux/i386 is +   to use int $0x80.  */ +#ifdef I386_USE_SYSENTER +# ifdef SHARED +#  define ENTER_KERNEL call *%gs:SYSINFO_OFFSET +# else +#  define ENTER_KERNEL call *_dl_sysinfo +# endif +#else +# define ENTER_KERNEL int $0x80 +#endif + +/* Linux takes system call arguments in registers: + +	syscall number	%eax	     call-clobbered +	arg 1		%ebx	     call-saved +	arg 2		%ecx	     call-clobbered +	arg 3		%edx	     call-clobbered +	arg 4		%esi	     call-saved +	arg 5		%edi	     call-saved +	arg 6		%ebp	     call-saved + +   The stack layout upon entering the function is: + +	24(%esp)	Arg# 6 +	20(%esp)	Arg# 5 +	16(%esp)	Arg# 4 +	12(%esp)	Arg# 3 +	 8(%esp)	Arg# 2 +	 4(%esp)	Arg# 1 +	  (%esp)	Return address + +   (Of course a function with say 3 arguments does not have entries for +   arguments 4, 5, and 6.) + +   The following code tries hard to be optimal.  A general assumption +   (which is true according to the data books I have) is that + +	2 * xchg	is more expensive than	pushl + movl + popl + +   Beside this a neat trick is used.  The calling conventions for Linux +   tell that among the registers used for parameters %ecx and %edx need +   not be saved.  Beside this we may clobber this registers even when +   they are not used for parameter passing. + +   As a result one can see below that we save the content of the %ebx +   register in the %edx register when we have less than 3 arguments +   (2 * movl is less expensive than pushl + popl). + +   Second unlike for the other registers we don't save the content of +   %ecx and %edx when we have more than 1 and 2 registers resp. + +   The code below might look a bit long but we have to take care for +   the pipelined processors (i586).  Here the `pushl' and `popl' +   instructions are marked as NP (not pairable) but the exception is +   two consecutive of these instruction.  This gives no penalty on +   other processors though.  */ + +#undef	DO_CALL +#define DO_CALL(syscall_name, args)			      		      \ +    PUSHARGS_##args							      \ +    DOARGS_##args							      \ +    movl $SYS_ify (syscall_name), %eax;					      \ +    ENTER_KERNEL							      \ +    POPARGS_##args + +#define PUSHARGS_0	/* No arguments to push.  */ +#define	DOARGS_0	/* No arguments to frob.  */ +#define	POPARGS_0	/* No arguments to pop.  */ +#define	_PUSHARGS_0	/* No arguments to push.  */ +#define _DOARGS_0(n)	/* No arguments to frob.  */ +#define	_POPARGS_0	/* No arguments to pop.  */ + +#define PUSHARGS_1	movl %ebx, %edx; L(SAVEBX1): PUSHARGS_0 +#define	DOARGS_1	_DOARGS_1 (4) +#define	POPARGS_1	POPARGS_0; movl %edx, %ebx; L(RESTBX1): +#define	_PUSHARGS_1	pushl %ebx; cfi_adjust_cfa_offset (4); \ +			cfi_rel_offset (ebx, 0); L(PUSHBX1): _PUSHARGS_0 +#define _DOARGS_1(n)	movl n(%esp), %ebx; _DOARGS_0(n-4) +#define	_POPARGS_1	_POPARGS_0; popl %ebx; cfi_adjust_cfa_offset (-4); \ +			cfi_restore (ebx); L(POPBX1): + +#define PUSHARGS_2	PUSHARGS_1 +#define	DOARGS_2	_DOARGS_2 (8) +#define	POPARGS_2	POPARGS_1 +#define _PUSHARGS_2	_PUSHARGS_1 +#define	_DOARGS_2(n)	movl n(%esp), %ecx; _DOARGS_1 (n-4) +#define	_POPARGS_2	_POPARGS_1 + +#define PUSHARGS_3	_PUSHARGS_2 +#define DOARGS_3	_DOARGS_3 (16) +#define POPARGS_3	_POPARGS_3 +#define _PUSHARGS_3	_PUSHARGS_2 +#define _DOARGS_3(n)	movl n(%esp), %edx; _DOARGS_2 (n-4) +#define _POPARGS_3	_POPARGS_2 + +#define PUSHARGS_4	_PUSHARGS_4 +#define DOARGS_4	_DOARGS_4 (24) +#define POPARGS_4	_POPARGS_4 +#define _PUSHARGS_4	pushl %esi; cfi_adjust_cfa_offset (4); \ +			cfi_rel_offset (esi, 0); L(PUSHSI1): _PUSHARGS_3 +#define _DOARGS_4(n)	movl n(%esp), %esi; _DOARGS_3 (n-4) +#define _POPARGS_4	_POPARGS_3; popl %esi; cfi_adjust_cfa_offset (-4); \ +			cfi_restore (esi); L(POPSI1): + +#define PUSHARGS_5	_PUSHARGS_5 +#define DOARGS_5	_DOARGS_5 (32) +#define POPARGS_5	_POPARGS_5 +#define _PUSHARGS_5	pushl %edi; cfi_adjust_cfa_offset (4); \ +			cfi_rel_offset (edi, 0); L(PUSHDI1): _PUSHARGS_4 +#define _DOARGS_5(n)	movl n(%esp), %edi; _DOARGS_4 (n-4) +#define _POPARGS_5	_POPARGS_4; popl %edi; cfi_adjust_cfa_offset (-4); \ +			cfi_restore (edi); L(POPDI1): + +#define PUSHARGS_6	_PUSHARGS_6 +#define DOARGS_6	_DOARGS_6 (40) +#define POPARGS_6	_POPARGS_6 +#define _PUSHARGS_6	pushl %ebp; cfi_adjust_cfa_offset (4); \ +			cfi_rel_offset (ebp, 0); L(PUSHBP1): _PUSHARGS_5 +#define _DOARGS_6(n)	movl n(%esp), %ebp; _DOARGS_5 (n-4) +#define _POPARGS_6	_POPARGS_5; popl %ebp; cfi_adjust_cfa_offset (-4); \ +			cfi_restore (ebp); L(POPBP1): + +#endif	/* __ASSEMBLER__ */ + + +/* Pointer mangling support.  */ +#if defined NOT_IN_libc && defined IS_IN_rtld +/* We cannot use the thread descriptor because in ld.so we use setjmp +   earlier than the descriptor is initialized.  Using a global variable +   is too complicated here since we have no PC-relative addressing mode.  */ +#else +# ifdef __ASSEMBLER__ +#  define PTR_MANGLE(reg)	xorl %gs:POINTER_GUARD, reg;		      \ +				roll $9, reg +#  define PTR_DEMANGLE(reg)	rorl $9, reg;				      \ +				xorl %gs:POINTER_GUARD, reg +# else +#  define PTR_MANGLE(var)	asm ("xorl %%gs:%c2, %0\n"		      \ +				     "roll $9, %0"			      \ +				     : "=r" (var)			      \ +				     : "0" (var),			      \ +				       "i" (offsetof (tcbhead_t,	      \ +						      pointer_guard))) +#  define PTR_DEMANGLE(var)	asm ("rorl $9, %0\n"			      \ +				     "xorl %%gs:%c2, %0"		      \ +				     : "=r" (var)			      \ +				     : "0" (var),			      \ +				       "i" (offsetof (tcbhead_t,	      \ +						      pointer_guard))) +# endif +#endif + +#endif /* linux/i386/sysdep.h */ 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..dc7fb2ec4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/i386/vfork.S @@ -0,0 +1,38 @@ +/* Copyright (C) 1999, 2002, 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> + +/* 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..07ee9d7dd --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/internaltypes.h @@ -0,0 +1,153 @@ +/* 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.  */ + +#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 which represent the clock.  COND_CLOCK_BITS is the number +   of bits reserved for the clock.  */ +#define COND_CLOCK_BITS	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; +}; + + +/* 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 sem +{ +  unsigned int count; +}; + + +/* 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..c435eff30 --- /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 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 +# define fptr __libc_pthread_functions.ptr___pthread_cleanup_upto +#else +# define fptr __pthread_cleanup_upto +#endif + +  if (fptr != NULL) +    fptr (env->__jmpbuf, CURRENT_STACK_FRAME); +} 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..4ad252800 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/libc_pthread_init.c @@ -0,0 +1,59 @@ +/* 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 <unistd.h> +#include <list.h> +#include "fork.h" +#include <tls.h> +#include <string.h> +#include <pthreadP.h> +#include <bits/libc-lock.h> + +libc_hidden_proto(memcpy) + +#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)); +#endif + +#ifndef TLS_MULTIPLE_THREADS_IN_TCB +  return &__libc_multiple_threads; +#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..36e28eb2a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelbarrier.sym @@ -0,0 +1,11 @@ +#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) 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..c5e797806 --- /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) +clock_bits	COND_CLOCK_BITS 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..f93891431 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevellock.c @@ -0,0 +1,131 @@ +/* low level locking for pthread library.  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 <sys/time.h> + + +void +__lll_lock_wait (int *futex) +{ +  do +    { +      int oldval = atomic_compare_and_exchange_val_acq (futex, 2, 1); +      if (oldval != 0) +	lll_futex_wait (futex, 2); +    } +  while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0); +} + + +int +__lll_timedlock_wait (int *futex, const struct timespec *abstime) +{ +  /* 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_acq (futex, 2, 1); +      if (oldval != 0) +	lll_futex_timed_wait (futex, 2, &rt); +    } +  while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0); + +  return 0; +} + + +/* These don't get included in libc.so  */ +#ifdef IS_IN_libpthread +int +lll_unlock_wake_cb (int *futex) +{ +  int val = atomic_exchange_rel (futex, 0); + +  if (__builtin_expect (val > 1, 0)) +    lll_futex_wake (futex, 1); + +  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.  */ +      if (lll_futex_timed_wait (tidp, tid, &rt) == -ETIMEDOUT) +	return ETIMEDOUT; +    } + +  return 0; +} + +#endif 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..e82c878d3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/lowlevelrwlock.sym @@ -0,0 +1,14 @@ +#include <stddef.h> +#include <stdio.h> +#include <bits/pthreadtypes.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) 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..f112b8a39 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h @@ -0,0 +1,215 @@ +/* Machine-specific pthread type layouts.  MIPS version. +   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.  */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H	1 + +#include <sgidefs.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 __pad1; +    unsigned long int __pad2; +    unsigned long int __pad3; +    /* 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 int __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/mips/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h new file mode 100644 index 000000000..c4440f9e9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2002, 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.  */ + +#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) + +/* Maximum value the semaphore can have.  */ +#define SEM_VALUE_MAX   (2147483647) + + +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..7edb28794 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h @@ -0,0 +1,216 @@ +/* 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.  */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H	1 + +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> +#include <atomic.h> +#include <sysdep.h> + + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 +#define FUTEX_REQUEUE		3 +#define FUTEX_CMP_REQUEUE	4 + +/* Initializer for compatibility lock.	*/ +#define LLL_MUTEX_LOCK_INITIALIZER (0) + +#define lll_futex_wait(futexp, val) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4,				      \ +			      (futexp), FUTEX_WAIT, (val), 0);		      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;		      \ +  }) + +#define lll_futex_timed_wait(futexp, val, timespec) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4,				      \ +			      (futexp), FUTEX_WAIT, (val), (timespec));	      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;		      \ +  }) + +#define lll_futex_wake(futexp, nr) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4,				      \ +			      (futexp), FUTEX_WAKE, (nr), 0);		      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;		      \ +  }) + +/* Returns non-zero if error happened, zero if success.  */ +#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 6,				      \ +			      (futexp), FUTEX_CMP_REQUEUE, (nr_wake),	      \ +			      (nr_move), (mutex), (val));		      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err);				      \ +  }) + + +static inline int __attribute__((always_inline)) +__lll_mutex_trylock(int *futex) +{ +  return atomic_compare_and_exchange_val_acq (futex, 1, 0) != 0; +} +#define lll_mutex_trylock(lock)	__lll_mutex_trylock (&(lock)) + + +static inline int __attribute__((always_inline)) +__lll_mutex_cond_trylock(int *futex) +{ +  return atomic_compare_and_exchange_val_acq (futex, 2, 0) != 0; +} +#define lll_mutex_cond_trylock(lock)	__lll_mutex_cond_trylock (&(lock)) + + +extern void __lll_lock_wait (int *futex) attribute_hidden; + +static inline void __attribute__((always_inline)) +__lll_mutex_lock(int *futex) +{ +  if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0) +    __lll_lock_wait (futex); +} +#define lll_mutex_lock(futex) __lll_mutex_lock (&(futex)) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_cond_lock (int *futex) +{ +  if (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0) +    __lll_lock_wait (futex); +} +#define lll_mutex_cond_lock(futex) __lll_mutex_cond_lock (&(futex)) + + +extern int __lll_timedlock_wait (int *futex, const struct timespec *) +	attribute_hidden; + +static inline int __attribute__ ((always_inline)) +__lll_mutex_timedlock (int *futex, const struct timespec *abstime) +{ +  int result = 0; +  if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0) +    result = __lll_timedlock_wait (futex, abstime); +  return result; +} +#define lll_mutex_timedlock(futex, abstime) \ +  __lll_mutex_timedlock (&(futex), abstime) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_unlock (int *futex) +{ +  int val = atomic_exchange_rel (futex, 0); +  if (__builtin_expect (val > 1, 0)) +    lll_futex_wake (futex, 1); +} +#define lll_mutex_unlock(futex) __lll_mutex_unlock(&(futex)) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_unlock_force (int *futex) +{ +  (void) atomic_exchange_rel (futex, 0); +  lll_futex_wake (futex, 1); +} +#define lll_mutex_unlock_force(futex) __lll_mutex_unlock_force(&(futex)) + + +#define lll_mutex_islocked(futex) \ +  (futex != 0) + + +/* Our internal lock implementation is identical to the binary-compatible +   mutex implementation. */ + +/* Type for lock object.  */ +typedef int lll_lock_t; + +/* Initializers for lock.  */ +#define LLL_LOCK_INITIALIZER		(0) +#define LLL_LOCK_INITIALIZER_LOCKED	(1) + +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + +/* The states of a lock are: +    0  -  untaken +    1  -  taken by one user +   >1  -  taken by more users */ + +#define lll_trylock(lock)	lll_mutex_trylock (lock) +#define lll_lock(lock)		lll_mutex_lock (lock) +#define lll_unlock(lock)	lll_mutex_unlock (lock) +#define lll_islocked(lock)	lll_mutex_islocked (lock) + +/* 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);	\ +  } 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;						\ +  }) + + +/* Conditional variable handling.  */ + +extern void __lll_cond_wait (pthread_cond_t *cond) +     attribute_hidden; +extern int __lll_cond_timedwait (pthread_cond_t *cond, +				 const struct timespec *abstime) +     attribute_hidden; +extern void __lll_cond_wake (pthread_cond_t *cond) +     attribute_hidden; +extern void __lll_cond_broadcast (pthread_cond_t *cond) +     attribute_hidden; + +#define lll_cond_wait(cond) \ +  __lll_cond_wait (cond) +#define lll_cond_timedwait(cond, abstime) \ +  __lll_cond_timedwait (cond, abstime) +#define lll_cond_wake(cond) \ +  __lll_cond_wake (cond) +#define lll_cond_broadcast(cond) \ +  __lll_cond_broadcast (cond) + +#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..649b752f5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c @@ -0,0 +1,94 @@ +/* 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); +} + + +int +__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); +	      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); +      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..5fee89235 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h @@ -0,0 +1,169 @@ +/* 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__ +# undef PSEUDO +# define PSEUDO(name, syscall_name, args)				      \ +      .align 2;								      \ +  L(pseudo_start):							      \ +      cfi_startproc;							      \ +  99: la t9,__syscall_error;						      \ +      jr t9;								      \ +  .type __##syscall_name##_nocancel, @function;				      \ +  .globl __##syscall_name##_nocancel;					      \ +  __##syscall_name##_nocancel:						      \ +    .set noreorder;							      \ +    .cpload t9;								      \ +    li v0, SYS_ify(syscall_name);					      \ +    syscall;								      \ +    .set reorder;							      \ +    bne a3, zero, SYSCALL_ERROR_LABEL;			       		      \ +    ret;								      \ +  .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;	      \ +  ENTRY (name)								      \ +    .set noreorder;							      \ +    .cpload t9;								      \ +    .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, SYSCALL_ERROR_LABEL;			       		      \ +    ret;								      \ +  L(pseudo_cancel):							      \ +    SAVESTK_##args;						              \ +    sw ra, 28(sp);							      \ +    cfi_rel_offset (ra, 28);						      \ +    sw gp, 32(sp);							      \ +    cfi_rel_offset (gp, 32);						      \ +    PUSHARGS_##args;			/* save syscall args */	      	      \ +    CENABLE;								      \ +    lw gp, 32(sp);							      \ +    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;								      \ +    lw gp, 32(sp);							      \ +    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, SYSCALL_ERROR_LABEL;					      \ +     RESTORESTK;						              \ +  L(pseudo_end):							      \ +    .set reorder; + +# undef PSEUDO_END +# define PSEUDO_END(sym) cfi_endproc; .end sym; .size sym,.-sym + +#endif + +# 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) + + +/* 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.  */ +# ifdef IS_IN_libpthread +#  define CENABLE	la t9, __pthread_enable_asynccancel; jalr t9; +#  define CDISABLE	la t9, __pthread_disable_asynccancel; jalr t9; +# elif defined IS_IN_librt +#  define CENABLE	la t9, __librt_enable_asynccancel; jalr t9; +#  define CDISABLE	la t9, __librt_disable_asynccancel; jalr t9; +# else +#  define CENABLE	la t9, __libc_enable_asynccancel; jalr t9; +#  define CDISABLE	la t9, __libc_disable_asynccancel; jalr t9; +# 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 diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep.h new file mode 100644 index 000000000..bfaab1f3a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep.h @@ -0,0 +1,302 @@ +/* Copyright (C) 2000, 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.  */ + +#ifndef _LINUX_MIPS_MIPS32_SYSDEP_H +#define _LINUX_MIPS_MIPS32_SYSDEP_H 1 + +#include <sys/syscall.h> + +/* There is some commonality.  */ +#include <sysdeps/mips/sysdep.h> + +/* For Linux we can use the system call table in the header file +	/usr/include/asm/unistd.h +   of the kernel.  But these symbols do not follow the SYS_* syntax +   so we have to redefine the `SYS_ify' macro here.  */ +#undef SYS_ify +#ifdef __STDC__ +# define SYS_ify(syscall_name)	__NR_##syscall_name +#else +# define SYS_ify(syscall_name)	__NR_/**/syscall_name +#endif + +#ifdef __ASSEMBLER__ + +/* We don't want the label for the error handler to be visible in the symbol +   table when we define it here.  */ +#ifdef __PIC__ +# define SYSCALL_ERROR_LABEL 99b +#endif + +#else   /* ! __ASSEMBLER__ */ + +/* Define a macro which expands into the inline wrapper code for a system +   call.  */ +#undef INLINE_SYSCALL +#define INLINE_SYSCALL(name, nr, args...)                               \ +  ({ INTERNAL_SYSCALL_DECL(err);					\ +     long result_var = INTERNAL_SYSCALL (name, err, nr, args);		\ +     if ( INTERNAL_SYSCALL_ERROR_P (result_var, err) )			\ +       {								\ +	 __set_errno (INTERNAL_SYSCALL_ERRNO (result_var, err));	\ +	 result_var = -1L;						\ +       }								\ +     result_var; }) + +#undef INTERNAL_SYSCALL_DECL +#define INTERNAL_SYSCALL_DECL(err) long err + +#undef INTERNAL_SYSCALL_ERROR_P +#define INTERNAL_SYSCALL_ERROR_P(val, err)   ((long) (err)) + +#undef INTERNAL_SYSCALL_ERRNO +#define INTERNAL_SYSCALL_ERRNO(val, err)     (val) + +#undef INTERNAL_SYSCALL +#define INTERNAL_SYSCALL(name, err, nr, args...) \ +	internal_syscall##nr (, "li\t$2, %2\t\t\t# " #name "\n\t",	\ +			      "i" (SYS_ify (name)), err, args) + +#undef INTERNAL_SYSCALL_NCS +#define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \ +	internal_syscall##nr (= number, , "r" (__v0), err, args) +#undef internal_syscall0 +#define internal_syscall0(ncs_init, cs_init, input, err, dummy...)	\ +({									\ +	long _sys_result;						\ +									\ +	{								\ +	register long __v0 __asm__("$2") ncs_init;			\ +	register long __a3 __asm__("$7");				\ +	__asm__ volatile (						\ +	".set\tnoreorder\n\t"						\ +	cs_init								\ +	"syscall\n\t"							\ +	".set reorder"							\ +	: "=r" (__v0), "=r" (__a3)					\ +	: input								\ +	: __SYSCALL_CLOBBERS);						\ +	err = __a3;							\ +	_sys_result = __v0;						\ +	}								\ +	_sys_result;							\ +}) + +#undef internal_syscall1 +#define internal_syscall1(ncs_init, cs_init, input, err, arg1)		\ +({									\ +	long _sys_result;						\ +									\ +	{								\ +	register long __v0 __asm__("$2") ncs_init;			\ +	register long __a0 __asm__("$4") = (long) arg1;			\ +	register long __a3 __asm__("$7");				\ +	__asm__ volatile (						\ +	".set\tnoreorder\n\t"						\ +	cs_init								\ +	"syscall\n\t"							\ +	".set reorder"							\ +	: "=r" (__v0), "=r" (__a3)					\ +	: input, "r" (__a0)						\ +	: __SYSCALL_CLOBBERS);						\ +	err = __a3;							\ +	_sys_result = __v0;						\ +	}								\ +	_sys_result;							\ +}) + +#undef internal_syscall2 +#define internal_syscall2(ncs_init, cs_init, input, err, arg1, arg2)	\ +({									\ +	long _sys_result;						\ +									\ +	{								\ +	register long __v0 __asm__("$2") ncs_init;			\ +	register long __a0 __asm__("$4") = (long) arg1;			\ +	register long __a1 __asm__("$5") = (long) arg2;			\ +	register long __a3 __asm__("$7");				\ +	__asm__ volatile (						\ +	".set\tnoreorder\n\t"						\ +	cs_init								\ +	"syscall\n\t"							\ +	".set\treorder"							\ +	: "=r" (__v0), "=r" (__a3)					\ +	: input, "r" (__a0), "r" (__a1)					\ +	: __SYSCALL_CLOBBERS);						\ +	err = __a3;							\ +	_sys_result = __v0;						\ +	}								\ +	_sys_result;							\ +}) + +#undef internal_syscall3 +#define internal_syscall3(ncs_init, cs_init, input, err, arg1, arg2, arg3)\ +({									\ +	long _sys_result;						\ +									\ +	{								\ +	register long __v0 __asm__("$2") ncs_init;			\ +	register long __a0 __asm__("$4") = (long) arg1;			\ +	register long __a1 __asm__("$5") = (long) arg2;			\ +	register long __a2 __asm__("$6") = (long) arg3;			\ +	register long __a3 __asm__("$7");				\ +	__asm__ volatile (						\ +	".set\tnoreorder\n\t"						\ +	cs_init								\ +	"syscall\n\t"							\ +	".set\treorder"							\ +	: "=r" (__v0), "=r" (__a3)					\ +	: input, "r" (__a0), "r" (__a1), "r" (__a2)			\ +	: __SYSCALL_CLOBBERS);						\ +	err = __a3;							\ +	_sys_result = __v0;						\ +	}								\ +	_sys_result;							\ +}) + +#undef internal_syscall4 +#define internal_syscall4(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4)\ +({									\ +	long _sys_result;						\ +									\ +	{								\ +	register long __v0 __asm__("$2") ncs_init;			\ +	register long __a0 __asm__("$4") = (long) arg1;			\ +	register long __a1 __asm__("$5") = (long) arg2;			\ +	register long __a2 __asm__("$6") = (long) arg3;			\ +	register long __a3 __asm__("$7") = (long) arg4;			\ +	__asm__ volatile (						\ +	".set\tnoreorder\n\t"						\ +	cs_init								\ +	"syscall\n\t"							\ +	".set\treorder"							\ +	: "=r" (__v0), "+r" (__a3)					\ +	: input, "r" (__a0), "r" (__a1), "r" (__a2)			\ +	: __SYSCALL_CLOBBERS);						\ +	err = __a3;							\ +	_sys_result = __v0;						\ +	}								\ +	_sys_result;							\ +}) + +/* We need to use a frame pointer for the functions in which we +   adjust $sp around the syscall, or debug information and unwind +   information will be $sp relative and thus wrong during the syscall.  As +   of GCC 3.4.3, this is sufficient.  */ +#define FORCE_FRAME_POINTER alloca (4) + +#undef internal_syscall5 +#define internal_syscall5(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5)\ +({									\ +	long _sys_result;						\ +									\ +	FORCE_FRAME_POINTER;						\ +	{								\ +	register long __v0 __asm__("$2") ncs_init;			\ +	register long __a0 __asm__("$4") = (long) arg1;			\ +	register long __a1 __asm__("$5") = (long) arg2;			\ +	register long __a2 __asm__("$6") = (long) arg3;			\ +	register long __a3 __asm__("$7") = (long) arg4;			\ +	__asm__ volatile (						\ +	".set\tnoreorder\n\t"						\ +	"subu\t$29, 32\n\t"						\ +	"sw\t%6, 16($29)\n\t"						\ +	cs_init								\ +	"syscall\n\t"							\ +	"addiu\t$29, 32\n\t"						\ +	".set\treorder"							\ +	: "=r" (__v0), "+r" (__a3)					\ +	: input, "r" (__a0), "r" (__a1), "r" (__a2),			\ +	  "r" ((long)arg5)						\ +	: __SYSCALL_CLOBBERS);						\ +	err = __a3;							\ +	_sys_result = __v0;						\ +	}								\ +	_sys_result;							\ +}) + +#undef internal_syscall6 +#define internal_syscall6(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5, arg6)\ +({									\ +	long _sys_result;						\ +									\ +	FORCE_FRAME_POINTER;						\ +	{								\ +	register long __v0 __asm__("$2") ncs_init;			\ +	register long __a0 __asm__("$4") = (long) arg1;			\ +	register long __a1 __asm__("$5") = (long) arg2;			\ +	register long __a2 __asm__("$6") = (long) arg3;			\ +	register long __a3 __asm__("$7") = (long) arg4;			\ +	__asm__ volatile (						\ +	".set\tnoreorder\n\t"						\ +	"subu\t$29, 32\n\t"						\ +	"sw\t%6, 16($29)\n\t"						\ +	"sw\t%7, 20($29)\n\t"						\ +	cs_init								\ +	"syscall\n\t"							\ +	"addiu\t$29, 32\n\t"						\ +	".set\treorder"							\ +	: "=r" (__v0), "+r" (__a3)					\ +	: input, "r" (__a0), "r" (__a1), "r" (__a2),			\ +	  "r" ((long)arg5), "r" ((long)arg6)				\ +	: __SYSCALL_CLOBBERS);						\ +	err = __a3;							\ +	_sys_result = __v0;						\ +	}								\ +	_sys_result;							\ +}) + +#undef internal_syscall7 +#define internal_syscall7(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5, arg6, arg7)\ +({									\ +	long _sys_result;						\ +									\ +	FORCE_FRAME_POINTER;						\ +	{								\ +	register long __v0 __asm__("$2") ncs_init;			\ +	register long __a0 __asm__("$4") = (long) arg1;			\ +	register long __a1 __asm__("$5") = (long) arg2;			\ +	register long __a2 __asm__("$6") = (long) arg3;			\ +	register long __a3 __asm__("$7") = (long) arg4;			\ +	__asm__ volatile (						\ +	".set\tnoreorder\n\t"						\ +	"subu\t$29, 32\n\t"						\ +	"sw\t%6, 16($29)\n\t"						\ +	"sw\t%7, 20($29)\n\t"						\ +	"sw\t%8, 24($29)\n\t"						\ +	cs_init								\ +	"syscall\n\t"							\ +	"addiu\t$29, 32\n\t"						\ +	".set\treorder"							\ +	: "=r" (__v0), "+r" (__a3)					\ +	: input, "r" (__a0), "r" (__a1), "r" (__a2),			\ +	  "r" ((long)arg5), "r" ((long)arg6), "r" ((long)arg7)		\ +	: __SYSCALL_CLOBBERS);						\ +	err = __a3;							\ +	_sys_result = __v0;						\ +	}								\ +	_sys_result;							\ +}) + +#undef __SYSCALL_CLOBBERS +#define __SYSCALL_CLOBBERS "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", \ +	"$14", "$15", "$24", "$25", "memory" + +#endif /* __ASSEMBLER__ */ + +#endif /* sysdeps/unix/sysv/linux/mips/sysdep.h */ 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..9d16fee56 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mq_notify.c @@ -0,0 +1,285 @@ +/* Copyright (C) 2004 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> + + +#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..9418417b4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/not-cancel.h @@ -0,0 +1,60 @@ +/* Uncancelable versions of cancelable interfaces.  Linux version. +   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 <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 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 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/Versions b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/Versions new file mode 100644 index 000000000..997784798 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/Versions @@ -0,0 +1,5 @@ +libpthread { +  GLIBC_2.3.4 { +    longjmp; siglongjmp; +  } +} 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..c94ed0c38 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h @@ -0,0 +1,216 @@ +/* Machine-specific pthread type layouts.  PowerPC version. +   Copyright (C) 2003, 2004 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 __pad1; +    unsigned long int __pad2; +    unsigned long int __pad3; +    /* 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 int __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..8123b418b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/bits/semaphore.h @@ -0,0 +1,44 @@ +/* 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) + +/* Maximum value the semaphore can have.  */ +#define SEM_VALUE_MAX   (2147483647) + + +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..1f2f481d6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h @@ -0,0 +1,241 @@ +/* Copyright (C) 2003, 2004 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> + + +#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 + +/* Initializer for compatibility lock.	*/ +#define LLL_MUTEX_LOCK_INITIALIZER (0) + +#define lll_futex_wait(futexp, val) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +									      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4,				      \ +			      (futexp), FUTEX_WAIT, (val), 0);		      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;		      \ +  }) + +#define lll_futex_timed_wait(futexp, val, timespec) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +									      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4,				      \ +			      (futexp), FUTEX_WAIT, (val), (timespec));	      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;		      \ +  }) + +#define lll_futex_wake(futexp, nr) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +									      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4,				      \ +			      (futexp), FUTEX_WAKE, (nr), 0);		      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;		      \ +  }) + +/* Returns non-zero if error happened, zero if success.  */ +#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +									      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 6,				      \ +			      (futexp), FUTEX_CMP_REQUEUE, (nr_wake),	      \ +			      (nr_move), (mutex), (val));		      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err);				      \ +  }) + +#ifdef UP +# define __lll_acq_instr	"" +# define __lll_rel_instr	"" +#else +# define __lll_acq_instr	"isync" +# define __lll_rel_instr	"sync" +#endif + +/* Set *futex to 1 if it is 0, atomically.  Returns the old value */ +#define __lll_trylock(futex) \ +  ({ int __val;								      \ +     __asm __volatile ("1:	lwarx	%0,0,%2\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" (1), "m" (*futex)		      \ +		       : "cr0", "memory");				      \ +     __val;								      \ +  }) + +#define lll_mutex_trylock(lock)	__lll_trylock (&(lock)) + +/* Set *futex to 2 if it is 0, atomically.  Returns the old value */ +#define __lll_cond_trylock(futex) \ +  ({ int __val;								      \ +     __asm __volatile ("1:	lwarx	%0,0,%2\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" (2), "m" (*futex)		      \ +		       : "cr0", "memory");				      \ +     __val;								      \ +  }) +#define lll_mutex_cond_trylock(lock)	__lll_cond_trylock (&(lock)) + + +extern void __lll_lock_wait (int *futex) attribute_hidden; + +#define lll_mutex_lock(lock) \ +  (void) ({								      \ +    int *__futex = &(lock);						      \ +    if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 1, 0),\ +			  0) != 0)					      \ +      __lll_lock_wait (__futex);					      \ +  }) + +#define lll_mutex_cond_lock(lock) \ +  (void) ({								      \ +    int *__futex = &(lock);						      \ +    if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 2, 0),\ +			  0) != 0)					      \ +      __lll_lock_wait (__futex);					      \ +  }) + +extern int __lll_timedlock_wait +  (int *futex, const struct timespec *) attribute_hidden; + +#define lll_mutex_timedlock(lock, abstime) \ +  ({									      \ +    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);			      \ +    __val;								      \ +  }) + +#define lll_mutex_unlock(lock) \ +  ((void) ({								      \ +    int *__futex = &(lock);						      \ +    int __val = atomic_exchange_rel (__futex, 0);			      \ +    if (__builtin_expect (__val > 1, 0))				      \ +      lll_futex_wake (__futex, 1);					      \ +  })) + +#define lll_mutex_unlock_force(lock) \ +  ((void) ({								      \ +    int *__futex = &(lock);						      \ +    *__futex = 0;							      \ +    __asm __volatile (__lll_rel_instr ::: "memory");			      \ +    lll_futex_wake (__futex, 1);					      \ +  })) + +#define lll_mutex_islocked(futex) \ +  (futex != 0) + + +/* Our internal lock implementation is identical to the binary-compatible +   mutex implementation. */ + +/* Type for lock object.  */ +typedef int lll_lock_t; + +/* Initializers for lock.  */ +#define LLL_LOCK_INITIALIZER		(0) +#define LLL_LOCK_INITIALIZER_LOCKED	(1) + +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + +/* The states of a lock are: +    0  -  untaken +    1  -  taken by one user +   >1  -  taken by more users */ + +#define lll_trylock(lock)	lll_mutex_trylock (lock) +#define lll_lock(lock)		lll_mutex_lock (lock) +#define lll_unlock(lock)	lll_mutex_unlock (lock) +#define lll_islocked(lock)	lll_mutex_islocked (lock) + +/* 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);					      \ +  } 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;								      \ +  }) + + +/* Conditional variable handling.  */ + +extern void __lll_cond_wait (pthread_cond_t *cond) +     attribute_hidden; +extern int __lll_cond_timedwait (pthread_cond_t *cond, +				 const struct timespec *abstime) +     attribute_hidden; +extern void __lll_cond_wake (pthread_cond_t *cond) +     attribute_hidden; +extern void __lll_cond_broadcast (pthread_cond_t *cond) +     attribute_hidden; + +#define lll_cond_wait(cond) \ +  __lll_cond_wait (cond) +#define lll_cond_timedwait(cond, abstime) \ +  __lll_cond_timedwait (cond, abstime) +#define lll_cond_wake(cond) \ +  __lll_cond_wake (cond) +#define lll_cond_broadcast(cond) \ +  __lll_cond_broadcast (cond) + +#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..e19579e84 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S @@ -0,0 +1,3 @@ +#define RESET_PID +#include <tcb-offsets.h> +#include <sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S> 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..0e6225624 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h @@ -0,0 +1,132 @@ +/* Cancellable system call stubs.  Linux/PowerPC version. +   Copyright (C) 2003, 2004, 2005 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., 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 + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args)				\ +  .section ".text";							\ +  ENTRY (name)								\ +    cfi_startproc;							\ +    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);							\ +    CGOTSETUP;								\ +    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);								\ +    CGOTRESTORE;							\ +    mtlr 4;								\ +    mtcr 0;								\ +    addi 1,1,48;							\ +    cfi_endproc; + +# 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 + +# define CGOTSETUP +# define CGOTRESTORE + +# 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 JUMPTARGET(__librt_enable_asynccancel) +#  define CDISABLE	bl JUMPTARGET(__librt_disable_asynccancel) +#  if defined HAVE_AS_REL16 && defined __PIC__ +#   undef CGOTSETUP +#   define CGOTSETUP							\ +    bcl 20,31,1f;							\ + 1: stw 30,44(1);							\ +    mflr 30;								\ +    addis 30,30,_GLOBAL_OFFSET_TABLE-1b@ha;				\ +    addi 30,30,_GLOBAL_OFFSET_TABLE-1b@l +#   undef CGOTRESTORE +#   define CGOTRESTORE							\ +    lwz 30,44(1) +#  endif +# 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 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..b7e2cf6e7 --- /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) +hidden_def (__vfork) +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/Versions b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/Versions new file mode 100644 index 000000000..3b111ddb5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/Versions @@ -0,0 +1,7 @@ +librt { +  GLIBC_2.3.3 { +    # Changed timer_t. +    timer_create; timer_delete; timer_getoverrun; timer_gettime; +    timer_settime; +  } +} 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..f87adf473 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S @@ -0,0 +1,3 @@ +#define RESET_PID +#include <tcb-offsets.h> +#include <sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S> 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..226aaafdc --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h @@ -0,0 +1,121 @@ +/* Cancellable system call stubs.  Linux/PowerPC64 version. +   Copyright (C) 2003, 2004 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., 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 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)								\ +    cfi_startproc;							\ +    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;							\ +    cfi_endproc; + +# 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 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..018132136 --- /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) +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..e1afff8a3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/pthread_once.c @@ -0,0 +1,100 @@ +/* Copyright (C) 2003, 2004 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); +} + + +int +__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); +    } + + +  /* 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); + +  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/sem_post.c b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/sem_post.c new file mode 100644 index 000000000..06b3bd0ab --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/powerpc/sem_post.c @@ -0,0 +1,42 @@ +/* sem_post -- post to a POSIX semaphore.  Powerpc version. +   Copyright (C) 2003, 2004 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) +{ +  int *futex = (int *) sem; + +  __asm __volatile (__lll_rel_instr ::: "memory"); +  int nr = atomic_increment_val (futex); +  int err = lll_futex_wake (futex, nr); +  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..7bee29784 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pt-raise.c @@ -0,0 +1,53 @@ +/* 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> + +extern __typeof(raise) __raise; +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 +} +libc_hidden_proto(raise) +weak_alias(__raise, raise) +libc_hidden_weak(raise) 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_attr_getaffinity.c b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c new file mode 100644 index 000000000..5a3d418a9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_getaffinity.c @@ -0,0 +1,56 @@ +/* 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_new (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.  */ +      size_t cnt; +      for (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; +} +weak_alias(__pthread_attr_getaffinity_new, pthread_attr_getaffinity_np) 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..e3414999c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_attr_setaffinity.c @@ -0,0 +1,82 @@ +/* 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 <limits.h> +#include <stdlib.h> +#include <string.h> +#include <pthreadP.h> + + +/* Defined in pthread_setaffinity.c.  */ +extern size_t __kernel_cpumask_size; +extern int __determine_cpumask_size (pid_t tid); + + +int +__pthread_attr_setaffinity_new (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.  */ +      size_t cnt; +      for (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; +} +weak_alias(__pthread_attr_setaffinity_new, pthread_attr_setaffinity_np) 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..3ca9d7d94 --- /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_new (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_new, __pthread_getaffinity_np) +strong_alias(__pthread_getaffinity_new, 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..155d3645f --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_getcpuclockid.c @@ -0,0 +1,111 @@ +/* pthread_getcpuclockid -- Get POSIX clockid_t for a pthread_t.  Linux version +   Copyright (C) 2000,2001,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; 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> +#include <bits/kernel-features.h> +#include <kernel-posix-cpu-timers.h> + + +#if !(__ASSUME_POSIX_CPU_TIMERS > 0) +int __libc_missing_posix_cpu_timers attribute_hidden; +#endif +#if !(__ASSUME_POSIX_TIMERS > 0) +int __libc_missing_posix_timers attribute_hidden; +#endif + +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 __NR_clock_getres +  /* The clockid_t value is a simple computation from the TID. +     But we do a clock_getres call to validate it if we aren't +     yet sure we have the kernel support.  */ + +  const clockid_t tidclock = MAKE_THREAD_CPUCLOCK (pd->tid, CPUCLOCK_SCHED); + +# if !(__ASSUME_POSIX_CPU_TIMERS > 0) +#  if !(__ASSUME_POSIX_TIMERS > 0) +  if (__libc_missing_posix_timers && !__libc_missing_posix_cpu_timers) +    __libc_missing_posix_cpu_timers = 1; +#  endif +  if (!__libc_missing_posix_cpu_timers) +    { +      INTERNAL_SYSCALL_DECL (err); +      int r = INTERNAL_SYSCALL (clock_getres, err, 2, tidclock, NULL); +      if (!INTERNAL_SYSCALL_ERROR_P (r, err)) +# endif +	{ +	  *clockid = tidclock; +	  return 0; +	} + +# if !(__ASSUME_POSIX_CPU_TIMERS > 0) +#  if !(__ASSUME_POSIX_TIMERS > 0) +      if (INTERNAL_SYSCALL_ERRNO (r, err) == ENOSYS) +	{ +	  /* The kernel doesn't support these calls at all.  */ +	  __libc_missing_posix_timers = 1; +	  __libc_missing_posix_cpu_timers = 1; +	} +      else +#  endif +	if (INTERNAL_SYSCALL_ERRNO (r, err) == EINVAL) +	  { +	    /* The kernel doesn't support these clocks at all.  */ +	    __libc_missing_posix_cpu_timers = 1; +	  } +      else +	return INTERNAL_SYSCALL_ERRNO (r, err); +    } +# endif +#endif + +#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..8d887e020 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_kill.c @@ -0,0 +1,70 @@ +/* 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 <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 (INVALID_TD_P (pd)) +    /* 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), +			  pd->tid, signo); +#else +# ifdef __NR_tgkill +  val = INTERNAL_SYSCALL (tgkill, err, 3, THREAD_GETMEM (THREAD_SELF, pid), +			  pd->tid, signo); +  if (INTERNAL_SYSCALL_ERROR_P (val, err) +      && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS) +# endif +    val = INTERNAL_SYSCALL (tkill, err, 2, pd->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..047c64322 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c @@ -0,0 +1,8 @@ +#include <pthreadP.h> + +#define LLL_MUTEX_LOCK(mutex) lll_mutex_cond_lock(mutex) +#define LLL_MUTEX_TRYLOCK(mutex) lll_mutex_cond_trylock(mutex) +#define __pthread_mutex_lock __pthread_mutex_cond_lock +#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..fa7b48904 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/pthread_setaffinity.c @@ -0,0 +1,86 @@ +/* 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 <alloca.h> +#include <errno.h> +#include <pthreadP.h> +#include <sysdep.h> +#include <sys/types.h> + + +size_t __kernel_cpumask_size; + + +/* Determine the current affinity.  As a side affect we learn +   about the size of the cpumask_t in the kernel.  */ +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; +} + + +int +__pthread_setaffinity_new (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.  */ +  size_t cnt; +  for (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); +  return (INTERNAL_SYSCALL_ERROR_P (res, err) +	  ? INTERNAL_SYSCALL_ERRNO (res, err) +	  : 0); +} +weak_alias(__pthread_setaffinity_new, pthread_setaffinity_np) 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..de794e4ab --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/raise.c @@ -0,0 +1,75 @@ +/* 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> + + +extern __typeof(raise) __raise; +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_proto(raise) +weak_alias(__raise, raise) +libc_hidden_weak(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..f6c3de4bc --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/register-atfork.c @@ -0,0 +1,108 @@ +/* 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 <stdlib.h> +#include <string.h> +#include "fork.h" + + +/* Lock to protect allocation and deallocation of fork handlers.  */ +lll_lock_t __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); + +  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; + +      newp->next = __fork_handlers; +      __fork_handlers = newp; +    } + +  /* Release the lock.  */ +  lll_unlock (__fork_lock); + +  return newp == NULL ? ENOMEM : 0; +} 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..7f0b67918 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_post.c @@ -0,0 +1,41 @@ +/* sem_post -- post to a POSIX semaphore.  Generic futex-using version. +   Copyright (C) 2003, 2004 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) +{ +  int *futex = (int *) sem; + +  int nr = atomic_increment_val (futex); +  int err = lll_futex_wake (futex, nr); +  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..79b11948c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c @@ -0,0 +1,97 @@ +/* sem_timedwait -- 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> +#include <pthreadP.h> + + +int +sem_timedwait (sem_t *sem, const struct timespec *abstime) +{ +  /* First check for cancellation.  */ +  CANCELLATION_P (THREAD_SELF); + +  int *futex = (int *) sem; +  int val; +  int err; + +  if (*futex > 0) +    { +      val = atomic_decrement_if_positive (futex); +      if (val > 0) +	return 0; +    } + +  err = -EINVAL; +  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) +    goto error_return; + +  do +    { +      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) +	goto error_return; + +      /* 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 (futex, 0, &rt); + +      /* Disable asynchronous cancellation.  */ +      __pthread_disable_asynccancel (oldtype); + +      if (err != 0 && err != -EWOULDBLOCK) +	goto error_return; + +      val = atomic_decrement_if_positive (futex); +    } +  while (val <= 0); + +  return 0; + + error_return: +  __set_errno (-err); +  return -1; +} 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..416d8634b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sem_wait.c @@ -0,0 +1,56 @@ +/* sem_wait -- 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> +#include <pthreadP.h> + + +int +__new_sem_wait (sem_t *sem) +{ +  /* First check for cancellation.  */ +  CANCELLATION_P (THREAD_SELF); + +  int *futex = (int *) sem; +  int err; + +  do +    { +      if (atomic_decrement_if_positive (futex) > 0) +	return 0; + +      /* Enable asynchronous cancellation.  Required by the standard.  */ +      int oldtype = __pthread_enable_asynccancel (); + +      err = lll_futex_wait (futex, 0); + +      /* Disable asynchronous cancellation.  */ +      __pthread_disable_asynccancel (oldtype); +    } +  while (err == 0 || err == -EWOULDBLOCK); + +  __set_errno (-err); +  return -1; +} +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..9bd7569c9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/Makefile.arch @@ -0,0 +1,84 @@ +# 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 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-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..969686dd5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h @@ -0,0 +1,168 @@ +/* Copyright (C) 2002, 2003, 2004, 2005, 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.  */ + +#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 int __flags; +    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..e6c5d845c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/bits/semaphore.h @@ -0,0 +1,39 @@ +/* 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) + +/* Maximum value the semaphore can have.  */ +#define SEM_VALUE_MAX   (2147483647) + + +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..dcedd2625 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/fork.c @@ -0,0 +1,31 @@ +/* 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 <stdio.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..94a24b46e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/libc-lowlevellock.S @@ -0,0 +1,19 @@ +/* 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 "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..062ce2871 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevel-atomic.h @@ -0,0 +1,81 @@ +/* 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.  */ + +#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, new, old) \ +	.align	2; \ +	mova	99f, r0; \ +	nop; \ +	mov	r15, r1; \ +	mov	_IMM4, r15; \ +98:	mov.l	mem, old; \ +	mov	old, new; \ +	add	reg, new; \ +	mov.l	new, 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..a5c916bb7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.S @@ -0,0 +1,296 @@ +/* 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 <pthread-errnos.h> +#include "lowlevel-atomic.h" + +	.text + +#define SYS_gettimeofday	__NR_gettimeofday + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + + +	.globl	__lll_mutex_lock_wait +	.type	__lll_mutex_lock_wait,@function +	.hidden	__lll_mutex_lock_wait +	.align	5 +	/* void __lll_mutex_lock_wait (int val, int *__futex) */ +__lll_mutex_lock_wait: +	mov	#2, r6 +	cmp/eq	r4, r6 +	mov	r5, r4 +	mov	#0, r7		/* No timeout.  */ +	mov	#FUTEX_WAIT, r5 + +	bf	2f + +1: +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD + +2: +	XCHG (r6, @r4, r2) +	tst	r2, r2 +	bf	1b + +	rts +	 nop +	.size	__lll_mutex_lock_wait,.-__lll_mutex_lock_wait + + +#ifdef NOT_IN_libc +	.globl	__lll_mutex_timedlock_wait +	.type	__lll_mutex_timedlock_wait,@function +	.hidden	__lll_mutex_timedlock_wait +	.align	5 +	/* int __lll_mutex_timedlock_wait (int val, int *__futex, +				       const struct timespec *abstime) */ +__lll_mutex_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	r9, @-r15 +	mov.l	r8, @-r15 +	mov	r6, r9 +	mov	r5, r8 + +	/* Stack frame for the timespec and timeval structs.  */ +	add	#-8, r15 + +1: +	/* Get current time.  */ +	mov	r15, r4 +	mov	#0, r5 +	mov	#SYS_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	5f		/* Time is already up.  */ + +	mov.l	r2, @r15	/* Store relative timeout.  */ +	mov.l	r3, @(4,r15) + +	mov	#1, r3 +	mov	#2, r6 +	CMPXCHG (r3, @r8, r6, r2) +	tst	r2, r2 +	bt	8f + +	mov	r8, r4 +	mov	#FUTEX_WAIT, r5 +	mov	r15, r7 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD +	mov	r0, r4 + +8: +	mov	#0, r3 +	CMPXCHG (r3, @r8, r6, r2) +	bf/s	7f +	mov	#0, r0 + +6: +	add	#8, r15 +	mov.l	@r15+, r8 +	rts +	mov.l	@r15+, r9 +7: +	/* Check whether the time expired.  */ +	mov	#-ETIMEDOUT, r1 +	cmp/eq	r5, r1 +	bt	5f + +	/* Make sure the current holder knows we are going to sleep.  */ +	XCHG (r2, @r8, r3) +	tst	r3, r3 +	bt/s	6b +	mov	#0, r0 +	bra	1b +	nop +3: +	rts +	mov	#EINVAL, r0 +5: +	bra	6b +	mov	#ETIMEDOUT, r0 + +.L1k: +	.word	1000 +	.align	2 +.L1g: +	.long	1000000000 + +	.size	__lll_mutex_timedlock_wait,.-__lll_mutex_timedlock_wait +#endif + + +#ifdef NOT_IN_libc +	.globl	lll_unlock_wake_cb +	.type	lll_unlock_wake_cb,@function +	.hidden	lll_unlock_wake_cb +	.align	5 +lll_unlock_wake_cb: +	DEC	(@r4, r2) +	tst	r2, r2 +	bt	1f + +	mov	#FUTEX_WAKE, r5 +	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 + +1: +	rts +	nop +	.size	lll_unlock_wake_cb,.-lll_unlock_wake_cb +#endif + + +	.globl	__lll_mutex_unlock_wake +	.type	__lll_mutex_unlock_wake,@function +	.hidden	__lll_mutex_unlock_wake +	.align	5 +	/* void __lll_mutex_unlock_wake(int *__futex) */ +__lll_mutex_unlock_wake: +	mov	#FUTEX_WAKE, r5 +	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 +	.size	__lll_mutex_unlock_wake,.-__lll_mutex_unlock_wake + + +#ifdef NOT_IN_libc +	.globl	__lll_timedwait_tid +	.type	__lll_timedwait_tid,@function +	.hidden	__lll_timedwait_tid +	.align	5 +__lll_timedwait_tid: +	mov.l	r9, @-r15 +	mov.l	r8, @-r15 +	mov	r4, r8 +	mov	r5, r9 + +	/* Stack frame for the timespec and timeval structs.  */ +	add	#-8, r15 + +2: +	/* Get current time.  */ +	mov	r15, r4 +	mov	#0, r5 +	mov	#SYS_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 +	mov	#FUTEX_WAIT, 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 + +.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..45339f5e0 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.h @@ -0,0 +1,294 @@ +/* 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.  */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H	1 + +#include <syscall.h> +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + + +/* Initializer for compatibility lock.  */ +#define LLL_MUTEX_LOCK_INITIALIZER		(0) +#define LLL_MUTEX_LOCK_INITIALIZER_LOCKED	(1) +#define LLL_MUTEX_LOCK_INITIALIZER_WAITERS	(2) + +extern int __lll_mutex_lock_wait (int val, int *__futex) attribute_hidden; +extern int __lll_mutex_timedlock_wait (int val, int *__futex, +				       const struct timespec *abstime) +     attribute_hidden; +extern int __lll_mutex_unlock_wake (int *__futex) attribute_hidden; + + +#define lll_mutex_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_MUTEX_LOCK_INITIALIZER_LOCKED), \ +	  "r" (LLL_MUTEX_LOCK_INITIALIZER) \ +	: "r0", "r1", "r2", "t", "memory"); \ +     __result; }) + +#define lll_mutex_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_MUTEX_LOCK_INITIALIZER_WAITERS), \ +	  "r" (LLL_MUTEX_LOCK_INITIALIZER) \ +	: "r0", "r1", "r2", "t", "memory"); \ +     __result; }) + +#define lll_mutex_lock(futex) \ +  (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) \ +	      __lll_mutex_lock_wait (__result, __futex); }) + +/* Special version of lll_mutex_lock which causes the unlock function to +   always wakeup waiters.  */ +#define lll_mutex_cond_lock(futex) \ +  (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_mutex_lock_wait (__result, __futex); }) + +#define lll_mutex_timedlock(futex, timeout) \ +  ({ 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_mutex_timedlock_wait (__result, __futex, timeout); \ +    __result; }) + +#define lll_mutex_unlock(futex) \ +  (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) \ +	      __lll_mutex_unlock_wake (__futex); }) + +#define lll_mutex_islocked(futex) \ +  (futex != 0) + + +/* We have a separate internal lock implementation which is not tied +   to binary compatibility.  */ + +/* Type for lock object.  */ +typedef int lll_lock_t; + +/* Initializers for lock.  */ +#define LLL_LOCK_INITIALIZER		(0) +#define LLL_LOCK_INITIALIZER_LOCKED	(1) + + +# 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) \ +  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") = FUTEX_WAIT;		      \ +    register unsigned long __r6 __asm ("r6") = (unsigned long) (val);	      \ +    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_futex_timed_wait(futex, val, timeout) \ +  ({									      \ +    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") = FUTEX_WAIT;		      \ +    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) \ +  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") = FUTEX_WAKE;		      \ +    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) + + +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + + +/* The states of a lock are: +    0  -  untaken +    1  -  taken by one user +    2  -  taken by more users */ + +#define lll_trylock(futex) lll_mutex_trylock (futex) +#define lll_lock(futex) lll_mutex_lock (futex) +#define lll_unlock(futex) lll_mutex_unlock (futex) + +#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.  */ + +extern int __lll_wait_tid (int *tid) attribute_hidden; +#define lll_wait_tid(tid) \ +  do {									      \ +    __typeof (tid) *__tid = &(tid);					      \ +    while (*__tid != 0)							      \ +      lll_futex_wait (__tid, *__tid);					      \ +  } 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; }) + + +/* Conditional variable handling.  */ + +extern void __lll_cond_wait (pthread_cond_t *cond) attribute_hidden; +extern int __lll_cond_timedwait (pthread_cond_t *cond, +				 const struct timespec *abstime) +     attribute_hidden; +extern void __lll_cond_wake (pthread_cond_t *cond) attribute_hidden; +extern void __lll_cond_broadcast (pthread_cond_t *cond) attribute_hidden; + + +#define lll_cond_wait(cond) \ +  __lll_cond_wait (cond) +#define lll_cond_timedwait(cond, abstime) \ +  __lll_cond_timedwait (cond, abstime) +#define lll_cond_wake(cond) \ +  __lll_cond_wake (cond) +#define lll_cond_broadcast(cond) \ +  __lll_cond_broadcast (cond) + +#endif  /* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/not-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/not-cancel.h new file mode 100644 index 000000000..eb83653d3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/not-cancel.h @@ -0,0 +1,82 @@ +/* Uncancelable versions of cancelable interfaces.  Linux/NPTL version. +   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 <sysdep.h> + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt +extern int __open_nocancel (const char *, int, ...) attribute_hidden; +extern int __close_nocancel (int) attribute_hidden; +extern int __read_nocancel (int, void *, size_t) attribute_hidden; +extern int __write_nocancel (int, const void *, size_t) attribute_hidden; +extern pid_t __waitpid_nocancel (pid_t, int *, int) attribute_hidden; + +libc_hidden_proto(__open_nocancel) +libc_hidden_proto(__close_nocancel) +libc_hidden_proto(__read_nocancel) +libc_hidden_proto(__write_nocancel) +libc_hidden_proto(__waitpid_nocancel) + +#else +#define __open_nocancel(name, ...) __open (name, __VA_ARGS__) +#define __close_nocancel(fd) __close (fd) +#define __read_nocancel(fd, buf, len) __read (fd, buf, len) +#define __write_nocancel(fd, buf, len) __write (fd, buf, len) +#define __waitpid_nocancel(pid, stat_loc, options) \ +  __waitpid (pid, stat_loc, options) +#endif + +/* Uncancelable open.  */ +#define open_not_cancel(name, flags, mode) \ +   __open_nocancel (name, flags, mode) +#define open_not_cancel_2(name, flags) \ +   __open_nocancel (name, flags) + +/* Uncancelable close.  */ +#define close_not_cancel(fd) \ +  __close_nocancel (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) \ +  __read_nocancel (fd, buf, n) + +/* Uncancelable write.  */ +#define write_not_cancel(fd, buf, n) \ +  __write_nocancel (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) \ +  __waitpid_nocancel (pid, stat_loc, options) +#else +# define waitpid_not_cancel(pid, stat_loc, options) \ +  INLINE_SYSCALL (wait4, 4, pid, stat_loc, options, NULL) +#endif 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..5391d5cc8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pt-initfini.c @@ -0,0 +1,143 @@ +/* Special .init and .fini section support for SH. NPTL 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 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\ +	 nop\n\ +	mova	.L23,r0\n\ +	mov.l	.L23,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\ +.L23:\n\ +	.long	__gmon_start__@PLT\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\ +	.section .text\n\ +	.align 5\n\ +	.weak	__gmon_start__\n\ +	.type	__gmon_start__,@function\n\ +__gmon_start__:\n\ +	mov.l	r14,@-r15\n\ +	mov	r15,r14\n\ +	mov	r14,r15\n\ +	rts	\n\ +	mov.l	@r15+,r14\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..608c7364c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_barrier_wait.S @@ -0,0 +1,191 @@ +/* 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 <lowlevelbarrier.h> +#include "lowlevel-atomic.h" + +#define FUTEX_WAIT	0 +#define FUTEX_WAKE	1 + + +	.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 +	mov	#FUTEX_WAIT, r5 +	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.  */ +	INC	(@(LEFT,r8), r2) +	mov.l	@(INIT_COUNT,r8), 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	#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.  */ +	INC	(@(LEFT,r8), r2) +	mov.l	@(INIT_COUNT,r8), 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	r2, r4 +	mov	r8, r5 +	mov.l	.Lwait0, r1 +	bsrf	r1 +	 add	#MUTEX, r5 +.Lwait0b: +	bra	2b +	 nop + +4: +	mov	r8, r4 +	mov.l	.Lwake0, r1 +	bsrf	r1 +	 add	#MUTEX, r4 +.Lwake0b: +	bra	5b +	 nop + +6: +	mov	r6, r9 +	mov	r8, r4 +	mov.l	.Lwake1, r1 +	bsrf	r1 +	 add	#MUTEX, r4 +.Lwake1b: +	bra	7b +	 mov	r9, r6 + +9: +	mov	r6, r9 +	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_mutex_lock_wait-.Lwait0b +.Lwake0: +	.long	__lll_mutex_unlock_wake-.Lwake0b +.Lwake1: +	.long	__lll_mutex_unlock_wake-.Lwake1b +.Lwake2: +	.long	__lll_mutex_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..36eccf1e6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_broadcast.S @@ -0,0 +1,210 @@ +/* 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 <lowlevelcond.h> +#include <bits/kernel-features.h> +#include "lowlevel-atomic.h" + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 +#define FUTEX_REQUEUE		3 +#define FUTEX_CMP_REQUEUE	4 + +#define EINVAL			22 + +	.text + +	/* int pthread_cond_broadcast (pthread_cond_t *cond) */ +	.globl	__pthread_cond_broadcast +	.type	__pthread_cond_broadcast, @function +	.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 + +	/* Wake up all threads.  */ +	mov	#FUTEX_CMP_REQUEUE, r5 +	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	.Lmwait5, r1 +	bsrf	r1 +	 mov	r2, r4 +.Lmwait5b: +	bra	2b +	 nop + +5: +	/* Unlock in loop requires wakeup.  */ +	mov	r8, r4 +#if cond_lock != 0 +	add	#cond_lock, r4 +#endif +	mov.l	.Lmwake5, r1 +	bsrf	r1 +	 nop +.Lmwake5b: +	bra	6b +	 nop + +7: +	/* Unlock in loop requires wakeup.  */ +	mov	r8, r4 +#if cond_lock != 0 +	add	#cond_lock, r4 +#endif +	mov.l	.Lmwake6, r1 +	bsrf	r1 +	 nop +.Lmwake6b: +	bra	8b +	 nop + +9: +	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 +	bra	10b +	 nop + +	.align	2 +.Lmwait5: +	.long	__lll_mutex_lock_wait-.Lmwait5b +.Lmwake5: +	.long	__lll_mutex_unlock_wake-.Lmwake5b +.Lmwake6: +	.long	__lll_mutex_unlock_wake-.Lmwake6b +	.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..d92f11cbb --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_signal.S @@ -0,0 +1,135 @@ +/* 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 <lowlevelcond.h> +#include <bits/kernel-features.h> +#include "lowlevel-atomic.h" + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 +#define FUTEX_REQUEUE		3 + +#define EINVAL			22 + +	.text + +	/* int pthread_cond_signal (pthread_cond_t *cond) */ +	.globl	__pthread_cond_signal +	.type	__pthread_cond_signal, @function +	.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	#FUTEX_WAKE, r5 +	mov	#1, r6 +	mov	#0, r7 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD + +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 +	rts +	 mov.l	@r15+, r8 + +1: +	/* Initial locking failed.  */ +	mov	r8, r5 +#if cond_lock != 0 +	add	#cond_lock, r5 +#endif +	mov.l	.Lmwait4, r1 +	bsrf	r1 +	 mov	r2, r4 +.Lmwait4b: +	bra	2b +	 nop + +5: +	/* Unlock in loop requires wakeup.  */ +	mov	r8, r4 +#if cond_lock != 0 +	add	#cond_lock, r4 +#endif +	mov.l	.Lmwake4, r1 +	bsrf	r1 +	 nop +.Lmwake4b: +	bra	6b +	 nop + +	.align	2 +.Lmwait4: +	.long	__lll_mutex_lock_wait-.Lmwait4b +.Lmwake4: +	.long	__lll_mutex_unlock_wake-.Lmwake4b +	.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..5812488b2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_timedwait.S @@ -0,0 +1,768 @@ +/* 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 <lowlevelcond.h> +#include <pthread-errnos.h> +#include "lowlevel-atomic.h" + +#define SYS_gettimeofday	__NR_gettimeofday + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + + +	.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 +	.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 << clock_bits), 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 << clock_bits) - 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	#SYS_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	#SYS_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	#FUTEX_WAIT, r5 +	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 << clock_bits), 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 << clock_bits) - 1), r1 +	not	r1, r1 +	mov.l	@(cond_nwaiters,r8),r0 +	tst	r1, r0 +	bf	25f + +	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 + +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 + +.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	.Lmwait2, r1 +	bsrf	r1 +	 mov	r2, r4 +.Lmwait2b: +	bra	2b +	 nop + +3: +	/* Unlock in loop requires wakeup.  */ +	mov	r8, r4 +#if cond_lock != 0 +	add	#cond_lock, r4 +#endif +	mov.l	.Lmwake2, r1 +	bsrf	r1 +	 nop +.Lmwake2b: +	bra	4b +	 nop + +5: +	/* Locking in loop failed.  */ +	mov	r8, r5 +#if cond_lock != 0 +	add	#cond_lock, r5 +#endif +	mov.l	.Lmwait3, r1 +	bsrf	r1 +	 mov	r2, r4 +.Lmwait3b: +	bra	6b +	 nop + +10: +	/* Unlock after loop requires wakeup.  */ +	mov	r8, r4 +#if cond_lock != 0 +	add	#cond_lock, r4 +#endif +	mov.l	.Lmwake3, r1 +	bsrf	r1 +	 nop +.Lmwake3b: +	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	.Lmwake4, r1 +	bsrf	r1 +	 nop +.Lmwake4b: +17: +	bra	18b +	 mov.l	@(24,r15), r0 + +	.align	2 +.Lmwait2: +	.long	__lll_mutex_lock_wait-.Lmwait2b +.Lmwake2: +	.long	__lll_mutex_unlock_wake-.Lmwake2b +.Lmwait3: +	.long	__lll_mutex_lock_wait-.Lmwait3b +.Lmwake3: +	.long	__lll_mutex_unlock_wake-.Lmwake3b +.Lmwake4: +	.long	__lll_mutex_unlock_wake-.Lmwake4b +	.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	.Lmwait5, r1 +	bsrf	r1 +	 mov	r2, r4 +.Lmwait5b: + +1: +	mov.l	@(broadcast_seq,r8), r0 +	mov.l	@(4,r15), r1 +	cmp/eq	r0, r1 +	bf	3f + +	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) + +	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 << clock_bits), 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 << clock_bits) - 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	.Lmwake5, r1 +	bsrf	r1 +	 nop +.Lmwake5b: + +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 +.Lmwait5: +	.long   __lll_mutex_lock_wait-.Lmwait5b +.Lmwake5: +        .long   __lll_mutex_unlock_wake-.Lmwake5b +.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..c7df9bf86 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_cond_wait.S @@ -0,0 +1,625 @@ +/* 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 <lowlevelcond.h> +#include "lowlevel-atomic.h" + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + + +	.text + +/* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)  */ +	.globl	__pthread_cond_wait +	.type	__pthread_cond_wait, @function +	.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 << clock_bits), 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	#FUTEX_WAIT, r5 +	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 << clock_bits), 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 << clock_bits) - 1), r1 +	not	r1, r1 +	mov.l	@(cond_nwaiters,r8),r0 +	tst	r1, r0 +	bf	17f + +	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 + +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 + +	.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	.Lmwait0, r1 +	bsrf	r1 +	 mov	r2, r4 +.Lmwait0b: +	bra	2b +	 nop +3: +	/* Unlock in loop requires waekup.  */ +	mov	r8, r4 +#if cond_lock != 0 +	add	#cond_lock, r4 +#endif +	mov.l	.Lmwake0, r1 +	bsrf	r1 +	 nop +.Lmwake0b: +	bra	4b +	 nop + +5: +	/* Locking in loop failed.  */ +	mov	r8, r5 +#if cond_lock != 0 +	add	#cond_lock, r5 +#endif +	mov.l	.Lmwait1, r1 +	bsrf	r1 +	 mov	r2, r4 +.Lmwait1b: +	bra	6b +	 nop + +10: +	/* Unlock after loop requires wakeup.  */ +	mov	r8, r4 +#if cond_lock != 0 +	add	#cond_lock, r4 +#endif +	mov.l	.Lmwake1, r1 +	bsrf	r1 +	 nop +.Lmwake1b: +	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	.Lmwake2, r1 +	bsrf	r1 +	 nop +.Lmwake2b: + +13: +	bra	14b +	 mov.l	@(12,r15), r0 + +	.align	2 +.Lmwait0: +	.long	__lll_mutex_lock_wait-.Lmwait0b +.Lmwake0: +	.long	__lll_mutex_unlock_wake-.Lmwake0b +.Lmwait1: +	.long	__lll_mutex_lock_wait-.Lmwait1b +.Lmwake1: +	.long	__lll_mutex_unlock_wake-.Lmwake1b +.Lmwake2: +	.long	__lll_mutex_unlock_wake-.Lmwake2b +	.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	.Lmwait3, r1 +	bsrf	r1 +	 mov	r2, r4 +.Lmwait3b: + +1: +	mov.l	@(broadcast_seq,r8), r0 +	mov.l	@(4,r15), r1 +	cmp/eq	r0, r1 +	bf	3f + +	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) + +	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 << clock_bits), 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 << clock_bits) - 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	.Lmwake3, r1 +	bsrf	r1 +	 nop +.Lmwake3b: + +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   .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 + +	.align	2 +.Lmwait3: +	.long   __lll_mutex_lock_wait-.Lmwait3b +.Lmwake3: +        .long   __lll_mutex_unlock_wake-.Lmwake3b +.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..de83dec1b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_once.S @@ -0,0 +1,245 @@ +/* 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 <unwindbuf.h> +#include <sysdep.h> +#include "lowlevel-atomic.h" + +#define FUTEX_WAIT	0 +#define FUTEX_WAKE	1 + +	.comm	__fork_generation, 4, 4 + +	.text +	.globl	__pthread_once +	.type	__pthread_once,@function +	.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.  */ +	mov	#FUTEX_WAIT, r5 +	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 +	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 + +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 +	mov	#FUTEX_WAKE, 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 + +	.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 + + +	.type	clear_once_control,@function +	.align	5 +clear_once_control: +	mov	#0, r0 +	mov.l	r0, @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 + +	rts +	 nop +	.size	clear_once_control,.-clear_once_control 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..ce1ab37c8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_rdlock.S @@ -0,0 +1,220 @@ +/* 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 <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include "lowlevel-atomic.h" + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + + +	.text + +	.globl	__pthread_rwlock_rdlock +	.type	__pthread_rwlock_rdlock,@function +	.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.l	@(FLAGS,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: +	mov	r8, r4 +	add	#READERS_WAKEUP, r4 +	mov	#FUTEX_WAIT, r5 +	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 + +1: +	mov	r8, r5 +#if MUTEX != 0 +	add	#MUTEX, r5 +#endif +	mov	r2, r4 +	mov.l	.Lwait0, r1 +	bsrf	r1 +	 nop +.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.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.l	.Lwake1, r1 +	bsrf	r1 +	 nop +.Lwake1b: +	bra	11b +	 nop + +12: +	mov	r8, r5 +#if MUTEX != 0 +	add	#MUTEX, r5 +#endif +	mov	r2, r4 +	mov.l	.Lwait1, r1 +	bsrf	r1 +	 nop +.Lwait1b: +	bra	13b +	 nop + +	.align	2 +.Lwait0: +	.long	__lll_mutex_lock_wait-.Lwait0b +.Lwake0: +	.long	__lll_mutex_unlock_wake-.Lwake0b +.Lwait1: +	.long	__lll_mutex_lock_wait-.Lwait1b +.Lwake1: +	.long	__lll_mutex_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..8a4e7d3bc --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedrdlock.S @@ -0,0 +1,280 @@ +/* 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 <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include "lowlevel-atomic.h" + +#define SYS_gettimeofday	__NR_gettimeofday +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + + +	.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.l	@(FLAGS,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	#SYS_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 +	mov	#FUTEX_WAIT, r5 +	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 + +	.align	2 +.L1k0: +	.long	1000 +.L1g0: +	.long	1000000000 + +1: +	mov	r8, r5 +#if MUTEX != 0 +	add	#MUTEX, r5 +#endif +	mov	r2, r4 +	mov.l	.Lwait2, r1 +	bsrf	r1 +	 nop +.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	r8, r4 +#if MUTEX != 0 +	add	#MUTEX, r4 +#endif +	mov.l	.Lwake2, r1 +	bsrf	r1 +	 nop +.Lwake2b: +	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.l	.Lwake3, r1 +	bsrf	r1 +	 nop +.Lwake3b: +	bra	11b +	 nop + +12: +	mov	r8, r5 +#if MUTEX != 0 +	add	#MUTEX, r5 +#endif +	mov	r2, r4 +	mov.l	.Lwait3, r1 +	bsrf	r1 +	 nop +.Lwait3b: +	bra	13b +	 nop + +16: +	bra	17b +	 mov	#-ETIMEDOUT, r3 + +19: +	bra	9b +	 mov	#EINVAL, r3 + +	.align	2 +.Lwait2: +	.long	__lll_mutex_lock_wait-.Lwait2b +.Lwake2: +	.long	__lll_mutex_unlock_wake-.Lwake2b +.Lwait3: +	.long	__lll_mutex_lock_wait-.Lwait3b +.Lwake3: +	.long	__lll_mutex_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..6284140a6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_timedwrlock.S @@ -0,0 +1,265 @@ +/* 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 <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include "lowlevel-atomic.h" + +#define SYS_gettimeofday	__NR_gettimeofday +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + + +	.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	#SYS_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 +	mov	#FUTEX_WAIT, r5 +	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 + +.L1k1: +	.word	1000 +	.align	2 +.L1g1: +	.long	1000000000 + +1: +	mov	r8, r5 +#if MUTEX != 0 +	add	#MUTEX, r5 +#endif +	mov	r2, r4 +	mov.l	.Lwait6, r1 +	bsrf	r1 +	 nop +.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	r8, r4 +#if MUTEX != 0 +	add	#MUTEX, r4 +#endif +	mov.l	.Lwake6, r1 +	bsrf	r1 +	 nop +.Lwake6b: +	bra	7b +	 mov	#0, 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.l	.Lwake7, r1 +	bsrf	r1 +	 nop +.Lwake7b: +	bra	11b +	 nop + +12: +	mov	r8, r5 +#if MUTEX != 0 +	add	#MUTEX, r5 +#endif +	mov	r2, r4 +	mov.l	.Lwait7, r1 +	bsrf	r1 +	 nop +.Lwait7b: +	bra	13b +	 nop + +16: +	bra	17b +	 mov	#-ETIMEDOUT, r3 + +	.align	2 +.Lwait6: +	.long	__lll_mutex_lock_wait-.Lwait6b +.Lwake6: +	.long	__lll_mutex_unlock_wake-.Lwake6b +.Lwait7: +	.long	__lll_mutex_lock_wait-.Lwait7b +.Lwake7: +	.long	__lll_mutex_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..74f32f8f9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_unlock.S @@ -0,0 +1,169 @@ +/* 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 <sysdep.h> +#include <lowlevelrwlock.h> +#include "lowlevel-atomic.h" + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + + +	.text + +	.globl	__pthread_rwlock_unlock +	.type	__pthread_rwlock_unlock,@function +	.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: +	mov	#FUTEX_WAKE, r5 +	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	r2, r4 +	mov.l	.Lwait8, r1 +	bsrf	r1 +	 nop +.Lwait8b: +	bra	2b +	 nop +3: +	mov	r8, r4 +#if MUTEX != 0 +	add	#MUTEX, r4 +#endif +	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.l	.Lwake9, r1 +	bsrf	r1 +	 nop +.Lwake9b: + +	mov.l	@r15+, r6 +	bra	8b +	 mov.l	@r15+, r4 + +	.align	2 +.Lwait8: +	.long	__lll_mutex_lock_wait-.Lwait8b +.Lwake8: +	.long	__lll_mutex_unlock_wake-.Lwake8b +.Lwake9: +	.long	__lll_mutex_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..d071f7f03 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/pthread_rwlock_wrlock.S @@ -0,0 +1,202 @@ +/* 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 <sysdep.h> +#include <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> +#include "lowlevel-atomic.h" + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + + +	.text + +	.globl	__pthread_rwlock_wrlock +	.type	__pthread_rwlock_wrlock,@function +	.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 +	mov	#FUTEX_WAIT, r5 +	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	r2, r4 +	mov.l	.Lwait4, r1 +	bsrf	r1 +	 nop +.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.l	.Lwake4, r1 +	bsrf	r1 +	 nop +.Lwake4b: +	bra	7b +	 mov	#0, r3 + +.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.l	.Lwake5, r1 +	bsrf	r1 +	 nop +.Lwake5b: +	bra	11b +	 nop + +12: +	mov	r8, r5 +#if MUTEX != 0 +	add	#MUTEX, r5 +#endif +	mov	r2, r4 +	mov.l	.Lwait5, r1 +	bsrf	r1 +	 nop +.Lwait5b: +	bra	13b +	 nop + +	.align	2 +.Lwait4: +	.long	__lll_mutex_lock_wait-.Lwait4b +.Lwake4: +	.long	__lll_mutex_unlock_wake-.Lwake4b +.Lwait5: +	.long	__lll_mutex_lock_wait-.Lwait5b +.Lwake5: +	.long	__lll_mutex_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..9755b7e16 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_post.S @@ -0,0 +1,84 @@ +/* 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 <pthread-errnos.h> +#include "lowlevel-atomic.h" + + +#define SYS_gettimeofday	__NR_gettimeofday +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + +	.text + +	.globl	__new_sem_post +	.type	__new_sem_post,@function +	.align	5 +__new_sem_post: +	INC	(@r4, r6) + +	mov	#FUTEX_WAKE, r5 +	mov	#0, r7 +	mov	#SYS_futex, r3 +	extu.b	r3, r3 +	trapa	#0x14 +	SYSCALL_INST_PAD + +	cmp/pz	r0 +	bf	1f +	rts +	 mov	#0, r0 + +1: +	mov	#EINVAL, r2 +	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: +#else +	mov.l	.Lerrloc3, r1 +	bsrf	r1 +	 nop +.Lerrloc3b: +#endif +	mov.l	r2, @r0 +	lds.l	@r15+, pr +	mov.l	@r15+, r12 +	rts +	 mov	#-1, r0 + +	.align	2 +.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..40782fcaf --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_timedwait.S @@ -0,0 +1,240 @@ +/* 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 <pthread-errnos.h> +#include <tcb-offsets.h> +#include "lowlevel-atomic.h" + + +#define SYS_gettimeofday	__NR_gettimeofday +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + +	.text + +	.globl	sem_timedwait +	.type	sem_timedwait,@function +	.align	5 +	cfi_startproc +sem_timedwait: +	/* First check for cancellation.  */ +	stc	gbr, r0 +	mov.w	.Lchand, r1 +	mov.l	@(r0,r1), r0 +	mov	#0xf9, r1 +	and	r1, r0 +	cmp/eq	#8, r0 +	bf	0f +	bra	10f +	 stc	gbr, r0 +0: +	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 +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset (r8, 0) +	mov.l	r9, @-r15 +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset (r9, 0) +	mov.l	r10, @-r15 +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset (r10, 0) +	mov.l	r12, @-r15 +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset (r12, 0) +	sts.l	pr, @-r15 +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset (pr, 0) +	add	#-8, r15 +	cfi_adjust_cfa_offset(8) +	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 +7: +	mov.l	.Lenable0, r1 +	bsrf	r1 +	 nop +.Lenable0b: +	mov	r0, r10 + +	/* Compute relative timeout.  */ +	mov	r15, r4 +	mov	#0, r5 +	mov	#SYS_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) + +	/* Futex call.  */ +	mov	r8, r4 +	mov	#FUTEX_WAIT, r5 +	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 + +	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 + +	add	#8, r15 +	lds.l	@r15+, pr +	mov.l	@r15+, r12 +	mov.l	@r15+, r10 +	mov.l	@r15+, r9 +	mov.l	@r15+, r8 +	rts +	 mov	#0, r0 + +3: +	neg	r0, r0 +6: +	mov	r0, r8 +	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	r8, @r0 +	add	#8, r15 +	lds.l	@r15+, pr +	mov.l	@r15+, r12 +	mov.l	@r15+, r10 +	mov.l	@r15+, r9 +	mov.l	@r15+, r8 +	rts +	 mov	#-1, r0 + +10: +	/* Canceled.  */ +	mov.w	.Lresult, r1 +	mov	#-1, r2 +	mov.l	r2, @(r0,r1) +	mov.w	.Lchand, r0 +	or.b	#0x10, @(r0,gbr) +	stc	gbr, r0 +	mov.w	.Lclbuf, r1 +	mov.l	.Lunwind, r2 +	braf	r2 +	 mov.l	@(r0,r1), r4 +.Lunwindb: +	cfi_endproc + +.L1k: +	.word	1000 +.Lchand: +	.word	CANCELHANDLING - TLS_PRE_TCB_SIZE +.Lresult: +	.word	RESULT - TLS_PRE_TCB_SIZE +.Lclbuf: +	.word	CLEANUP_JMP_BUF - TLS_PRE_TCB_SIZE +	.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 +.Lunwind: +	.long	HIDDEN_JUMPTARGET (__pthread_unwind)-.Lunwindb +	.size	sem_timedwait,.-sem_timedwait 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..00c61f3bb --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_trywait.S @@ -0,0 +1,89 @@ +/* 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 <pthread-errnos.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..7d13fa130 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sem_wait.S @@ -0,0 +1,166 @@ +/* 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 <pthread-errnos.h> +#include <tcb-offsets.h> +#include "lowlevel-atomic.h" + + +#define SYS_gettimeofday	__NR_gettimeofday +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + +	.text + +	.globl	__new_sem_wait +	.type	__new_sem_wait,@function +	.align	5 +	cfi_startproc +__new_sem_wait: +	/* First check for cancellation.  */ +	stc	gbr, r0 +	mov.w	.Lchand, r1 +	mov.l	@(r0,r1), r0 +	mov	#0xf9, r1 +	and	r1, r0 +	cmp/eq	#8, r0 +	bt	5f + +	mov.l	r8, @-r15 +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset (r8, 0) +	mov.l	r10, @-r15 +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset (r10, 0) +	mov.l	r12, @-r15 +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset (r12, 0) +	sts.l	pr, @-r15 +	cfi_adjust_cfa_offset(4) +	cfi_rel_offset (pr, 0) +	mov	r4, r8 +3: +	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 +	bra	9f +	 mov	#0, r0 + +1: +	mov.l	.Lenable0, r1 +	bsrf	r1 +	 nop +.Lenable0b: +	mov	r0, r10 + +	mov	r8, r4 +	mov	#FUTEX_WAIT, r5 +	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 + +	tst	r0, r0 +	bt	3b +	cmp/eq	#-EWOULDBLOCK, r0 +	bt	3b +	neg	r0, r0 + +	mov	r0, 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 +	mov	#-1, r0 +9: +	lds.l	@r15+, pr +	mov.l	@r15+, r12 +	mov.l	@r15+, r10 +	rts +	 mov.l	@r15+, r8 +5: +	/* Canceled.  */ +	stc	gbr, r0 +	mov.w	.Lresult, r1 +	mov	#-1, r2 +	mov.l	r2, @(r0,r1) +	mov.w	.Lchand, r0 +	or.b	#0x10, @(r0,gbr) +	stc	gbr, r0 +	mov.w	.Lclbuf, r1 +	mov.l	.Lunwind, r2 +	braf	r2 +	 mov.l	@(r0,r1), r4 +.Lunwindb: +	cfi_endproc + +.Lchand: +	.word	CANCELHANDLING - TLS_PRE_TCB_SIZE +.Lresult: +	.word	RESULT - TLS_PRE_TCB_SIZE +.Lclbuf: +	.word	CLEANUP_JMP_BUF - TLS_PRE_TCB_SIZE +	.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 +.Lunwind: +	.long	HIDDEN_JUMPTARGET (__pthread_unwind)-.Lunwindb +	.size	__new_sem_wait,.-__new_sem_wait +	weak_alias(__new_sem_wait, sem_wait) 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/sh4/sysdep.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sh4/sysdep.h new file mode 100644 index 000000000..1aed1a14a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sh4/sysdep.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_next <sysdep.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..dbaa44385 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sysdep-cancel.h @@ -0,0 +1,247 @@ +/* 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 <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; \ + .LCFI0: \ +    add _IMM16,r15; \ +    SAVE_ARGS_##args; \ + .LCFI1: \ +    CENABLE; \ +    LOAD_ARGS_##args; \ +    add _IMP16,r15; \ + .LCFI2: \ +    lds.l @r15+,pr; \ + .LCFI3: \ +    DO_CALL(syscall_name, args); \ +    SYSCALL_INST_PAD; \ +    sts.l pr,@-r15; \ + .LCFI4: \ +    mov.l r0,@-r15; \ + .LCFI5: \ +    CDISABLE; \ +    mov.l @r15+,r0; \ + .LCFI6: \ +    lds.l @r15+,pr; \ + .LCFI7: \ +    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: \ + /* Create unwinding information for the syscall wrapper.  */ \ + .section .eh_frame,"a",@progbits; \ + .Lframe1: \ +    .ualong .LECIE1-.LSCIE1; \ + .LSCIE1: \ +    .ualong 0x0; \ +    .byte   0x1; \ +    AUGMENTATION_STRING; \ +    .uleb128 0x1; \ +    .sleb128 -4; \ +    .byte   0x11; \ +    AUGMENTATION_PARAM; \ +    .byte   0xc; \ +    .uleb128 0xf; \ +    .uleb128 0x0; \ +    .align 2; \ + .LECIE1: \ + .LSFDE1: \ +    .ualong .LEFDE1-.LASFDE1; \ + .LASFDE1: \ +    .ualong .LASFDE1-.Lframe1; \ +    START_SYMBOL_REF; \ +    .ualong .Lpseudo_end - .Lpseudo_start; \ +    AUGMENTATION_PARAM_FDE; \ +    .byte   0x4; \ +    .ualong .LCFI0-.Lpseudo_start; \ +    .byte   0xe; \ +    .uleb128 0x4; \ +    .byte   0x91; \ +    .uleb128 0x1; \ +    .byte   0x4; \ +    .ualong .LCFI1-.LCFI0; \ +    .byte   0xe; \ +    .uleb128 0x14; \ +    FRAME_REG_##args; \ +    .byte   0x4; \ +    .ualong .LCFI2-.LCFI1; \ +    .byte   0xe; \ +    .uleb128 0x4; \ +    .byte   0x4; \ +    .ualong .LCFI3-.LCFI2; \ +    .byte   0xe; \ +    .uleb128 0x0; \ +    .byte   0xd1; \ +    .byte   0x4; \ +    .ualong .LCFI4-.LCFI3; \ +    .byte   0xe; \ +    .uleb128 0x4; \ +    .byte   0x91; \ +    .uleb128 0x1; \ +    .byte   0x4; \ +    .ualong .LCFI5-.LCFI4; \ +    .byte   0xe; \ +    .uleb128 0x8; \ +    .byte   0x80; \ +    .uleb128 0x2; \ +    .byte   0x4; \ +    .ualong .LCFI6-.LCFI5; \ +    .byte   0xe; \ +    .uleb128 0x4; \ +    .byte   0xc0; \ +    .byte   0x4; \ +    .ualong .LCFI7-.LCFI6; \ +    .byte   0xe; \ +    .uleb128 0x0; \ +    .byte   0xd1; \ +    .align 2; \ + .LEFDE1: \ + .previous + +# ifdef SHARED +#  define AUGMENTATION_STRING .string "zR" +#  define AUGMENTATION_PARAM .uleb128 1; .byte 0x1b +#  define AUGMENTATION_PARAM_FDE .uleb128 0 +#  define START_SYMBOL_REF .long .Lpseudo_start-. +# else +#  define AUGMENTATION_STRING .ascii "\0" +#  define AUGMENTATION_PARAM +#  define AUGMENTATION_PARAM_FDE +#  define START_SYMBOL_REF .long .Lpseudo_start +# endif + +# define FRAME_REG_0	/* Nothing.  */ +# define FRAME_REG_1	FRAME_REG_0; .byte 0x84; .uleb128 5 +# define FRAME_REG_2	FRAME_REG_1; .byte 0x85; .uleb128 4 +# define FRAME_REG_3	FRAME_REG_2; .byte 0x86; .uleb128 3 +# define FRAME_REG_4	FRAME_REG_3; .byte 0x87; .uleb128 2 +# define FRAME_REG_5	FRAME_REG_4 +# define FRAME_REG_6	FRAME_REG_5 + +# 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) +# define SAVE_ARGS_2	SAVE_ARGS_1; mov.l r5,@(4,r15) +# define SAVE_ARGS_3	SAVE_ARGS_2; mov.l r6,@(8,r15) +# define SAVE_ARGS_4	SAVE_ARGS_3; mov.l r7,@(12,r15) +# 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 diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sysdep.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sysdep.h new file mode 100644 index 000000000..7e9223b70 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sh/sysdep.h @@ -0,0 +1,224 @@ +/* Copyright (C) 1992,1993,1995,1996,1997,1998,1999,2000,2002,2003,2004 +	Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>, August 1995. +   Changed by Kaz Kojima, <kkojima@rr.iij4u.or.jp>. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License 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 _LINUX_SH_SYSDEP_H +#define _LINUX_SH_SYSDEP_H 1 + +/* There is some commonality.  */ +#include <sysdeps/unix/sh/sysdep.h> + +/* For Linux we can use the system call table in the header file +	/usr/include/asm/unistd.h +   of the kernel.  But these symbols do not follow the SYS_* syntax +   so we have to redefine the `SYS_ify' macro here.  */ +#undef SYS_ify +#define SYS_ify(syscall_name)	(__NR_##syscall_name) + + +#ifdef __ASSEMBLER__ + +/* Linux uses a negative return value to indicate syscall errors, +   unlike most Unices, which use the condition codes' carry flag. + +   Since version 2.1 the return value of a system call might be +   negative even if the call succeeded.  E.g., the `lseek' system call +   might return a large offset.  Therefore we must not anymore test +   for < 0, but test for a real error by making sure the value in R0 +   is a real error number.  Linus said he will make sure the no syscall +   returns a value in -1 .. -4095 as a valid result so we can savely +   test with -4095.  */ + +#define _IMM1 #-1 +#define _IMM12 #-12 +#undef	PSEUDO +#define	PSEUDO(name, syscall_name, args) \ + .text; \ + ENTRY (name); \ +    DO_CALL (syscall_name, args); \ +    mov r0,r1; \ +    mov _IMM12,r2; \ +    shad r2,r1; \ +    not r1,r1; \ +    tst r1,r1; \ +    bf .Lpseudo_end; \ +    SYSCALL_ERROR_HANDLER; \ + .Lpseudo_end: + +#undef	PSEUDO_END +#define	PSEUDO_END(name) \ +  END (name) + +#undef	PSEUDO_NOERRNO +#define	PSEUDO_NOERRNO(name, syscall_name, args) \ + .text; \ + ENTRY (name); \ +    DO_CALL (syscall_name, args) + +#undef	PSEUDO_END_NOERRNO +#define	PSEUDO_END_NOERRNO(name) \ +  END (name) + +#define ret_NOERRNO ret + +#define	PSEUDO_ERRVAL(name, syscall_name, args) \ + .text; \ + ENTRY (name); \ +    DO_CALL (syscall_name, args); + +#undef	PSEUDO_END_ERRVAL +#define	PSEUDO_END_ERRVAL(name) \ +  END (name) + +#define ret_ERRVAL ret + +#ifndef __PIC__ +# define SYSCALL_ERROR_HANDLER	\ +	mov.l 0f,r1; \ +	jmp @r1; \ +	 mov r0,r4; \ +	.align 2; \ +     0: .long __syscall_error + +#include <libc/sysdeps/linux/sh/syscall_error.S> +#else +# ifdef RTLD_PRIVATE_ERRNO + +#  define SYSCALL_ERROR_HANDLER	\ +	neg r0,r1; \ +	mov.l 0f,r12; \ +	mova 0f,r0; \ +	add r0,r12; \ +	mov.l 1f,r0; \ +	mov.l r1,@(r0,r12) +	bra .Lpseudo_end; \ +	 mov _IMM1,r0; \ +	.align 2; \ +     0: .long _GLOBAL_OFFSET_TABLE_; \ +     1: .long rtld_errno@GOTOFF + +# elif defined _LIBC_REENTRANT + +#  if USE___THREAD + +#   ifndef NOT_IN_libc +#    define SYSCALL_ERROR_ERRNO __libc_errno +#   else +#    define SYSCALL_ERROR_ERRNO errno +#   endif +#   define SYSCALL_ERROR_HANDLER \ +	neg r0,r1; \ +	mov r12,r2; \ +	mov.l 0f,r12; \ +	mova 0f,r0; \ +	add r0,r12; \ +	mov.l 1f,r0; \ +	stc gbr, r4; \ +	mov.l @(r0,r12),r0; \ +	bra .Lskip; \ +	add r4,r0; \ +	.align 2; \ +	1: .long SYSCALL_ERROR_ERRNO@GOTTPOFF; \ +	.Lskip: \ +	mov r2,r12; \ +	mov.l r1,@r0; \ +	bra .Lpseudo_end; \ +	mov _IMM1,r0; \ +	.align 2; \ +	0: .long _GLOBAL_OFFSET_TABLE_ +#  else + +#   define SYSCALL_ERROR_HANDLER \ +	neg r0,r1; \ +	mov.l r14,@-r15; \ +	mov.l r12,@-r15; \ +	mov.l r1,@-r15; \ +	mov.l 0f,r12; \ +	mova 0f,r0; \ +	add r0,r12; \ +	sts.l pr,@-r15; \ +	mov r15,r14; \ +	mov.l 1f,r1; \ +	bsrf r1; \ +         nop; \ +     2: mov r14,r15; \ +	lds.l @r15+,pr; \ +	mov.l @r15+,r1; \ +	mov.l r1,@r0; \ +	mov.l @r15+,r12; \ +	mov.l @r15+,r14; \ +	bra .Lpseudo_end; \ +	 mov _IMM1,r0; \ +	.align 2; \ +     0: .long _GLOBAL_OFFSET_TABLE_; \ +     1: .long PLTJMP(C_SYMBOL_NAME(__errno_location))-(2b-.) +/* A quick note: it is assumed that the call to `__errno_location' does +   not modify the stack!  */ +#  endif +# else + +/* Store (-r0) into errno through the GOT.  */ +#  define SYSCALL_ERROR_HANDLER						      \ +	neg r0,r1; \ +	mov r12,r2; \ +	mov.l 0f,r12; \ +	mova 0f,r0; \ +	add r0,r12; \ +	mov.l 1f,r0; \ +	mov.l @(r0,r12),r0; \ +	mov r2,r12; \ +	mov.l r1,@r0; \ +	bra .Lpseudo_end; \ +	 mov _IMM1,r0; \ +	.align 2; \ +     0: .long _GLOBAL_OFFSET_TABLE_; \ +     1: .long errno@GOT +# endif	/* _LIBC_REENTRANT */ +#endif	/* __PIC__ */ + +# ifdef NEED_SYSCALL_INST_PAD +#  define SYSCALL_INST_PAD \ +	or r0,r0; or r0,r0; or r0,r0; or r0,r0; or r0,r0 +# else +#  define SYSCALL_INST_PAD +# endif + +#define SYSCALL_INST0	trapa #0x10 +#define SYSCALL_INST1	trapa #0x11 +#define SYSCALL_INST2	trapa #0x12 +#define SYSCALL_INST3	trapa #0x13 +#define SYSCALL_INST4	trapa #0x14 +#define SYSCALL_INST5	mov.l @(0,r15),r0; trapa #0x15 +#define SYSCALL_INST6	mov.l @(0,r15),r0; mov.l @(4,r15),r1; trapa #0x16 + +#undef	DO_CALL +#define DO_CALL(syscall_name, args)	\ +    mov.l 1f,r3;			\ +    SYSCALL_INST##args;			\ +    SYSCALL_INST_PAD;			\ +    bra 2f;				\ +     nop;				\ +    .align 2;				\ + 1: .long SYS_ify (syscall_name);	\ + 2: + +#endif	/* __ASSEMBLER__ */ + +#endif /* linux/sh/sysdep.h */ 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..41fa97ff4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/smp.h @@ -0,0 +1,52 @@ +/* Determine whether the host has multiple processors.  Linux version. +   Copyright (C) 1996, 2002, 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 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/sysctl.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) +{ +  static const int sysctl_args[] = { CTL_KERN, KERN_VERSION }; +  char buf[512]; +  size_t reslen = sizeof (buf); + +  /* Try reading the number using `sysctl' first.  */ +  if (sysctl ((int *) sysctl_args, +		sizeof (sysctl_args) / sizeof (sysctl_args[0]), +		buf, &reslen, NULL, 0) < 0) +    { +      /* 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 +	  || (reslen = read_not_cancel (fd, buf, sizeof (buf))) <= 0) +	/* This also didn't work.  We give up and say it's a UP machine.  */ +	buf[0] = '\0'; + +      close_not_cancel_no_status (fd); +    } + +  return strstr (buf, "SMP") != NULL; +} 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..b54731075 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile.arch @@ -0,0 +1,66 @@ +# 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 + +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/Versions b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Versions new file mode 100644 index 000000000..d10277248 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Versions @@ -0,0 +1,6 @@ +libpthread { +  GLIBC_2.3.3 { +    # Changed PTHREAD_STACK_MIN. +    pthread_attr_setstack; pthread_attr_setstacksize; +  } +} 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..e082ea8f0 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/local_lim.h @@ -0,0 +1,89 @@ +/* Minimum guaranteed maximum values for system limits.  Linux/SPARC version. +   Copyright (C) 1993-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 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 + +/* 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 + +/* 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 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..459d1ca79 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h @@ -0,0 +1,218 @@ +/* Machine-specific pthread type layouts.  SPARC version. +   Copyright (C) 2003, 2004 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 __pad1; +    unsigned long int __pad2; +    unsigned long int __pad3; +    /* 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 int __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..7f3a32832 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/bits/semaphore.h @@ -0,0 +1,44 @@ +/* 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) + +/* Maximum value the semaphore can have.  */ +#define SEM_VALUE_MAX   (2147483647) + + +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/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..e9ec4df1e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.c @@ -0,0 +1,131 @@ +/* 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> + + +/* These functions don't get included in libc.so  */ +void +__lll_lock_wait (int *futex) +{ +  do +    { +      int oldval = atomic_compare_and_exchange_val_24_acq (futex, 2, 1); +      if (oldval != 0) +	lll_futex_wait (futex, 2); +    } +  while (atomic_compare_and_exchange_val_24_acq (futex, 2, 0) != 0); +} + + +#ifdef IS_IN_libpthread +int +__lll_timedlock_wait (int *futex, const struct timespec *abstime) +{ +  /* 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); +    } +  while (atomic_compare_and_exchange_val_24_acq (futex, 2, 0) != 0); + +  return 0; +} + +int +lll_unlock_wake_cb(int* futex) +{ +    int val = atomic_exchange_24_rel(futex, 0); + +    if( __builtin_expect( val > 1, 0 ) ) { +        lll_futex_wake( futex, 1 ); +    } + +    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) == -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..4db6fb0b4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.h @@ -0,0 +1,258 @@ +/* Copyright (C) 2003, 2004, 2006, 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 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> + + +#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) + +/* Initializer for compatibility lock.	*/ +#define LLL_MUTEX_LOCK_INITIALIZER (0) + +#define lll_futex_wait(futexp, val) \ +  lll_futex_timed_wait (futexp, val, NULL) + +#define lll_futex_timed_wait(futexp, val, timespec) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),		  \ +			      FUTEX_WAIT, (val), (timespec));			      \ +    __ret;								      \ +  }) + +#define lll_futex_wake(futexp, nr) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),		      \ +			      FUTEX_WAKE, (nr), 0);					      \ +    __ret;								      \ +  }) + +/* Returns non-zero if error happened, zero if success.  */ +#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),		      \ +			      FUTEX_CMP_REQUEUE, (nr_wake), (nr_move), (mutex), (val));	      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err);				      \ +  }) + +#define lll_robust_dead(futexv) \ +  do									      \ +    {									      \ +      int *__futexp = &(futexv);					      \ +      atomic_or (__futexp, FUTEX_OWNER_DIED);				      \ +      lll_futex_wake (__futexp, 1);				      \ +    }									      \ +  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) 1 +#else +# define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +									      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),		      \ +			      FUTEX_WAKE_OP,    \ +			      (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_mutex_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_mutex_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 (int *futex) attribute_hidden; +extern int __lll_robust_lock_wait (int *futex) attribute_hidden; + +static inline void +__attribute__ ((always_inline)) +__lll_lock (int *futex) +{ +  int val = atomic_compare_and_exchange_val_24_acq (futex, 1, 0); + +  if (__builtin_expect (val != 0, 0)) +    { +	__lll_lock_wait (futex); +    } +} +#define lll_mutex_lock(futex) __lll_lock (&(futex)) + +static inline int +__attribute__ ((always_inline)) +__lll_robust_lock (int *futex, int id) +{ +  int result = 0; +  if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0) +    result = __lll_robust_lock_wait (futex); +  return result; +} +#define lll_robust_lock(futex, id) \ +  __lll_robust_lock (&(futex), id) + +static inline void +__attribute__ ((always_inline)) +__lll_cond_lock (int *futex) +{ +  int val = atomic_compare_and_exchange_val_24_acq (futex, 2, 0); + +  if (__builtin_expect (val != 0, 0)) +    __lll_lock_wait (futex); +} +#define lll_mutex_cond_lock(futex) __lll_cond_lock (&(futex)) + +#define lll_robust_cond_lock(futex, id) \ +  __lll_robust_lock (&(futex), (id) | FUTEX_WAITERS) + + +extern int __lll_timedlock_wait (int *futex, const struct timespec *) attribute_hidden; +extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *) attribute_hidden; + +static inline int +__attribute__ ((always_inline)) +__lll_timedlock (int *futex, const struct timespec *abstime) +{ +  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); +  return result; +} +#define lll_mutex_timedlock(futex, abstime) \ +  __lll_timedlock (&(futex), abstime) + +static inline int +__attribute__ ((always_inline)) +__lll_robust_timedlock (int *futex, const struct timespec *abstime, +			int id) +{ +  int result = 0; +  if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0) +    result = __lll_robust_timedlock_wait (futex, abstime); +  return result; +} +#define lll_robust_timedlock(futex, abstime, id) \ +  __lll_robust_timedlock (&(futex), abstime, id) + +#define lll_mutex_unlock(lock) \ +  ((void) ({								      \ +    int *__futex = &(lock);						      \ +    int __val = atomic_exchange_24_rel (__futex, 0);			      \ +    if (__builtin_expect (__val > 1, 0))				      \ +      lll_futex_wake (__futex, 1);				      \ +  })) + +#define lll_robust_unlock(lock) \ +  ((void) ({								      \ +    int *__futex = &(lock);						      \ +    int __val = atomic_exchange_rel (__futex, 0);			      \ +    if (__builtin_expect (__val & FUTEX_WAITERS, 0))			      \ +      lll_futex_wake (__futex, 1);				      \ +  })) + +#define lll_mutex_islocked(futex) \ +  (futex != 0) + +/* We have a separate internal lock implementation which is not tied +   to binary compatibility.  */ + +/* Type for lock object.  */ +typedef int lll_lock_t; + +/* Initializers for lock.  */ +#define LLL_LOCK_INITIALIZER		(0) +#define LLL_LOCK_INITIALIZER_LOCKED	(1) + +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + +#define lll_trylock(lock)	lll_mutex_trylock (lock) +#define lll_lock(lock)		lll_mutex_lock (lock) +#define lll_unlock(lock)	lll_mutex_unlock (lock) +#define lll_islocked(lock)	lll_mutex_islocked (lock) + + +/* 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);	\ +    }							\ +  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_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_once.c new file mode 100644 index 000000000..3b07cc127 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pthread_once.c @@ -0,0 +1,94 @@ +/* Copyright (C) 2003, 2004 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); +} + + +int +__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); +	      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); +      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/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/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h new file mode 100644 index 000000000..ad650d040 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h @@ -0,0 +1,105 @@ +/* Copyright (C) 2002, 2003, 2004 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 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..1a3827789 --- /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) + +hidden_def (vfork) +weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/Versions b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/Versions new file mode 100644 index 000000000..3b111ddb5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc64/Versions @@ -0,0 +1,7 @@ +librt { +  GLIBC_2.3.3 { +    # Changed timer_t. +    timer_create; timer_delete; timer_getoverrun; timer_gettime; +    timer_settime; +  } +} 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/sysdep.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep.h new file mode 100644 index 000000000..744e587a3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep.h @@ -0,0 +1,65 @@ +#ifndef _LINUX_SPARC_SYSDEP_H +#define _LINUX_SPARC_SYSDEP_H 1 + +#include <sysdeps/unix/sysdep.h> + +#undef ENTRY +#undef END + +#ifdef __ASSEMBLER__ + +#define LOADSYSCALL(x) mov __NR_##x, %g1 + +#define ENTRY(name)                 \ +    .align 4;                       \ +    .global C_SYMBOL_NAME(name);    \ +    .type   name, @function;        \ +C_LABEL(name)                       \ +    cfi_startproc; + +#define END(name)                   \ +    cfi_endproc;                    \ +    .size name, . - name + +#define LOC(name) .L##name + +	/* If the offset to __syscall_error fits into a signed 22-bit +	 * immediate branch offset, the linker will relax the call into +	 * a normal branch. +	 */ +#undef PSEUDO +#undef PSEUDO_END +#undef PSEUDO_NOERRNO +#undef PSEUDO_ERRVAL + +#define PSEUDO(name, syscall_name, args)	\ +	.text;					\ +	.globl		__syscall_error;	\ +ENTRY(name);					\ +	LOADSYSCALL(syscall_name);		\ +	ta		0x10;			\ +	bcc		1f;			\ +	 mov		%o7, %g1;		\ +	call		__syscall_error;	\ +	 mov		%g1, %o7;		\ +1: + +#define PSEUDO_NOERRNO(name, syscall_name, args)\ +	.text;					\ +ENTRY(name);					\ +	LOADSYSCALL(syscall_name);		\ +	ta		0x10; + +#define PSEUDO_ERRVAL(name, syscall_name, args)	\ +	.text;					\ +ENTRY(name);					\ +	LOADSYSCALL(syscall_name);		\ +	ta		0x10; + +#define PSEUDO_END(name)			\ +	END(name) + + +#endif + +#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/timer_create.c b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_create.c new file mode 100644 index 000000000..9f02fe3b2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_create.c @@ -0,0 +1,236 @@ +/* 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; 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; + +	      /* 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; +	      sev.sigev_value.sival_ptr = newp; +	      sev.sigev_signo = SIGTIMER; +	      sev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID; +	      /* This is the thread ID of the helper thread.  */ +	      sev._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)) +		{ +		  *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..9b92446d5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_delete.c @@ -0,0 +1,93 @@ +/* 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_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) +	{ +# 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..7afc5ec6f --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_getoverr.c @@ -0,0 +1,80 @@ +/* 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..924c524ba --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/timer_routines.c @@ -0,0 +1,159 @@ +/* Copyright (C) 2003, 2004, 2005 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" + + +#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 timer *tk = (struct timer *) arg; + +  /* Call the user-provided function.  */ +  tk->thrfunc (tk->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; + +	      /* That the signal we are waiting for.  */ +	      pthread_t th; +	      (void) pthread_create (&th, &tk->attr, timer_sigev_thread, tk); +	    } +	  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 it 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..35955238b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c @@ -0,0 +1,110 @@ +/* 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 <stdlib.h> +#include "fork.h" +#include <atomic.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); + +  /* 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 +    { +      if (runp->dso_handle == dso_handle) +	{ +	  if (lastp == NULL) +	    __fork_handlers = runp->next; +	  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); + +  /* 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); + +      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..f059e2db2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Makefile.arch @@ -0,0 +1,73 @@ +# 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 + +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 \ +		   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_cond_timedwait.S pthread_cond_wait.S pthread_spin_unlock.S + +libc_a_SSRC += libc-lowlevellock.S + + +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 + +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 +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/Versions b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Versions new file mode 100644 index 000000000..3b111ddb5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/Versions @@ -0,0 +1,7 @@ +librt { +  GLIBC_2.3.3 { +    # Changed timer_t. +    timer_create; timer_delete; timer_getoverrun; timer_gettime; +    timer_settime; +  } +} 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..57edbbbfb --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/bits/semaphore.h @@ -0,0 +1,44 @@ +/* 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) + +/* Maximum value the semaphore can have.  */ +#define SEM_VALUE_MAX   (2147483647) + + +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..675a997e9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/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/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..1e461ad41 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S @@ -0,0 +1,282 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 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> + +	.text + +#ifndef LOCK +# ifdef UP +#  define LOCK +# else +#  define LOCK lock +# endif +#endif + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + +/* For the calculation see asm/vsyscall.h.  */ +#define VSYSCALL_ADDR_vgettimeofday	0xffffffffff600000 + + +	.globl	__lll_mutex_lock_wait +	.type	__lll_mutex_lock_wait,@function +	.hidden	__lll_mutex_lock_wait +	.align	16 +__lll_mutex_lock_wait: +	pushq	%r10 +	pushq	%rdx + +	xorq	%r10, %r10	/* No timeout.  */ +	movl	$2, %edx +#if FUTEX_WAIT == 0 +	xorl	%esi, %esi +#else +	movl	$FUTEX_WAIT, %esi +#endif + +	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 +	popq	%r10 +	retq +	.size	__lll_mutex_lock_wait,.-__lll_mutex_lock_wait + + +#ifdef NOT_IN_libc +	.globl	__lll_mutex_timedlock_wait +	.type	__lll_mutex_timedlock_wait,@function +	.hidden	__lll_mutex_timedlock_wait +	.align	16 +__lll_mutex_timedlock_wait: +	/* Check for a valid timeout value.  */ +	cmpq	$1000000000, 8(%rdx) +	jae	3f + +	pushq	%r8 +	pushq	%r9 +	pushq	%r12 +	pushq	%r13 +	pushq	%r14 + +	/* Stack frame for the timespec and timeval structs.  */ +	subq	$16, %rsp + +	movq	%rdi, %r12 +	movq	%rdx, %r13 + +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	5f		/* Time is already up.  */ + +	/* Futex call.  */ +	movq	%rdi, (%rsp)	/* Store relative timeout.  */ +	movq	%rsi, 8(%rsp) + +	movl	$1, %eax +	movl	$2, %edx +	LOCK +	cmpxchgl %edx, (%r12) + +	testl	%eax, %eax +	je	8f + +	movq	%rsp, %r10 +#if FUTEX_WAIT == 0 +	xorl	%esi, %esi +#else +	movl	$FUTEX_WAIT, %esi +#endif +	movq	%r12, %rdi +	movl	$SYS_futex, %eax +	syscall +	movq	%rax, %rcx + +8:				/* NB: %edx == 2 */ +	xorl	%eax, %eax +	LOCK +	cmpxchgl %edx, (%rdi) +	jnz	7f + +6:	addq	$16, %rsp +	popq	%r14 +	popq	%r13 +	popq	%r12 +	popq	%r9 +	popq	%r8 +	retq + +	/* Check whether the time expired.  */ +7:	cmpq	$-ETIMEDOUT, %rcx +	je	5f + +	/* Make sure the current holder knows we are going to sleep.  */ +	movl	%edx, %eax +	xchgl	%eax, (%rdi) +	testl	%eax, %eax +	jz	6b +	jmp	1b + +3:	movl	$EINVAL, %eax +	retq + +5:	movl	$ETIMEDOUT, %eax +	jmp	6b +	.size	__lll_mutex_timedlock_wait,.-__lll_mutex_timedlock_wait +#endif + + +#ifdef NOT_IN_libc +	.globl	lll_unlock_wake_cb +	.type	lll_unlock_wake_cb,@function +	.hidden	lll_unlock_wake_cb +	.align	16 +lll_unlock_wake_cb: +	pushq	%rsi +	pushq	%rdx + +	LOCK +	addl	$1, (%rdi) +	jng	1f + +	popq	%rdx +	popq	%rsi +	retq +	.size	lll_unlock_wake_cb,.-lll_unlock_wake_cb +#endif + + +	.globl	__lll_mutex_unlock_wake +	.type	__lll_mutex_unlock_wake,@function +	.hidden	__lll_mutex_unlock_wake +	.align	16 +__lll_mutex_unlock_wake: +	pushq	%rsi +	pushq	%rdx + +	movl	$0, (%rdi) +	movl	$FUTEX_WAKE, %esi +	movl	$1, %edx	/* Wake one thread.  */ +	movl	$SYS_futex, %eax +	syscall + +	popq	%rdx +	popq	%rsi +	retq +	.size	__lll_mutex_unlock_wake,.-__lll_mutex_unlock_wake + + +#ifdef NOT_IN_libc +	.globl	__lll_timedwait_tid +	.type	__lll_timedwait_tid,@function +	.hidden	__lll_timedwait_tid +	.align	16 +__lll_timedwait_tid: +	pushq	%r12 +	pushq	%r13 + +	movq	%rdi, %r12 +	movq	%rsi, %r13 + +	subq	$16, %rsp + +	/* 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 +#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 +	popq	%r13 +	popq	%r12 +	retq + +1:	cmpq	$-ETIMEDOUT, %rax +	jne	2b + +6:	movl	$ETIMEDOUT, %eax +	jmp	8b +	.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..c9f30e962 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h @@ -0,0 +1,342 @@ +/* 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.  */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H	1 + +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> +#include <atomic.h> +#include <sysdep.h> + +#ifndef LOCK_INSTR +# ifdef UP +#  define LOCK_INSTR	/* nothing */ +# else +#  define LOCK_INSTR "lock;" +# endif +#endif + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + + +/* Initializer for compatibility lock.  */ +#define LLL_MUTEX_LOCK_INITIALIZER		(0) +#define LLL_MUTEX_LOCK_INITIALIZER_LOCKED	(1) +#define LLL_MUTEX_LOCK_INITIALIZER_WAITERS	(2) + +/* Delay in spinlock loop.  */ +#define BUSY_WAIT_NOP          __asm__ ("rep; nop") + + +#define lll_futex_wait(futex, val) \ +  do {									      \ +    int __ignore;							      \ +    register __typeof (val) _val __asm__ ("edx") = (val);			      \ +    __asm__ __volatile ("xorq %%r10, %%r10\n\t"				      \ +		      "syscall"						      \ +		      : "=a" (__ignore)					      \ +		      : "0" (SYS_futex), "D" (futex), "S" (FUTEX_WAIT),	      \ +			"d" (_val)					      \ +		      : "memory", "cc", "r10", "r11", "cx");		      \ +  } while (0) + + +#define lll_futex_wake(futex, nr) \ +  do {									      \ +    int __ignore;							      \ +    register __typeof (nr) _nr __asm__ ("edx") = (nr);			      \ +    __asm__ __volatile ("syscall"						      \ +		      : "=a" (__ignore)					      \ +		      : "0" (SYS_futex), "D" (futex), "S" (FUTEX_WAKE),	      \ +			"d" (_nr)					      \ +		      : "memory", "cc", "r10", "r11", "cx");		      \ +  } while (0) + + +/* Does not preserve %eax and %ecx.  */ +extern int __lll_mutex_lock_wait (int *__futex, int __val) attribute_hidden; +/* Does not preserver %eax, %ecx, and %edx.  */ +extern int __lll_mutex_timedlock_wait (int *__futex, int __val, +				       const struct timespec *__abstime) +     attribute_hidden; +/* Preserves all registers but %eax.  */ +extern int __lll_mutex_unlock_wait (int *__futex) attribute_hidden; + + +/* NB: in the lll_mutex_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.  */ +#define lll_mutex_trylock(futex) \ +  ({ int ret;								      \ +     __asm__ __volatile (LOCK_INSTR "cmpxchgl %2, %1"			      \ +		       : "=a" (ret), "=m" (futex)			      \ +		       : "r" (LLL_MUTEX_LOCK_INITIALIZER_LOCKED), "m" (futex),\ +			 "0" (LLL_MUTEX_LOCK_INITIALIZER)		      \ +		       : "memory");					      \ +     ret; }) + + +#define lll_mutex_cond_trylock(futex) \ +  ({ int ret;								      \ +     __asm__ __volatile (LOCK_INSTR "cmpxchgl %2, %1"			      \ +		       : "=a" (ret), "=m" (futex)			      \ +		       : "r" (LLL_MUTEX_LOCK_INITIALIZER_WAITERS),	      \ +			 "m" (futex), "0" (LLL_MUTEX_LOCK_INITIALIZER)	      \ +		       : "memory");					      \ +     ret; }) + + +#define lll_mutex_lock(futex) \ +  (void) ({ int ignore1, ignore2, ignore3;				      \ +	    __asm__ __volatile (LOCK_INSTR "cmpxchgl %0, %2\n\t"		      \ +			      "jnz 1f\n\t"				      \ +			      ".subsection 1\n"				      \ +			      "1:\tleaq %2, %%rdi\n\t"			      \ +			      "subq $128, %%rsp\n\t"			      \ +			      "callq __lll_mutex_lock_wait\n\t"		      \ +			      "addq $128, %%rsp\n\t"			      \ +			      "jmp 2f\n\t"				      \ +			      ".previous\n"				      \ +			      "2:"					      \ +			      : "=S" (ignore1), "=&D" (ignore2), "=m" (futex),\ +				"=a" (ignore3)				      \ +			      : "0" (1), "m" (futex), "3" (0)		      \ +			      : "cx", "r11", "cc", "memory"); }) + + +#define lll_mutex_cond_lock(futex) \ +  (void) ({ int ignore1, ignore2, ignore3;				      \ +	    __asm__ __volatile (LOCK_INSTR "cmpxchgl %0, %2\n\t"		      \ +			      "jnz 1f\n\t"				      \ +			      ".subsection 1\n"				      \ +			      "1:\tleaq %2, %%rdi\n\t"			      \ +			      "subq $128, %%rsp\n\t"			      \ +			      "callq __lll_mutex_lock_wait\n\t"		      \ +			      "addq $128, %%rsp\n\t"			      \ +			      "jmp 2f\n\t"				      \ +			      ".previous\n"				      \ +			      "2:"					      \ +			      : "=S" (ignore1), "=&D" (ignore2), "=m" (futex),\ +				"=a" (ignore3)				      \ +			      : "0" (2), "m" (futex), "3" (0)		      \ +			      : "cx", "r11", "cc", "memory"); }) + + +#define lll_mutex_timedlock(futex, timeout) \ +  ({ int _result, ignore1, ignore2, ignore3;				      \ +     __asm__ __volatile (LOCK_INSTR "cmpxchgl %2, %4\n\t"			      \ +		       "jnz 1f\n\t"					      \ +		       ".subsection 1\n"				      \ +		       "1:\tleaq %4, %%rdi\n\t"				      \ +		       "movq %8, %%rdx\n\t"				      \ +		       "subq $128, %%rsp\n\t"				      \ +		       "callq __lll_mutex_timedlock_wait\n\t"		      \ +		       "addq $128, %%rsp\n\t"				      \ +		       "jmp 2f\n\t"					      \ +		       ".previous\n"					      \ +		       "2:"						      \ +		       : "=a" (_result), "=&D" (ignore1), "=S" (ignore2),      \ +			 "=&d" (ignore3), "=m" (futex)			      \ +		       : "0" (0), "2" (1), "m" (futex), "m" (timeout)	      \ +		       : "memory", "cx", "cc", "r10", "r11");		      \ +     _result; }) + + +#define lll_mutex_unlock(futex) \ +  (void) ({ int ignore;							      \ +            __asm__ __volatile (LOCK_INSTR "decl %0\n\t"			      \ +			      "jne 1f\n\t"				      \ +			      ".subsection 1\n"				      \ +			      "1:\tleaq %0, %%rdi\n\t"			      \ +			      "subq $128, %%rsp\n\t"			      \ +			      "callq __lll_mutex_unlock_wake\n\t"	      \ +			      "addq $128, %%rsp\n\t"			      \ +			      "jmp 2f\n\t"				      \ +			      ".previous\n"				      \ +			      "2:"					      \ +			      : "=m" (futex), "=&D" (ignore)		      \ +			      : "m" (futex)				      \ +			      : "ax", "cx", "r11", "cc", "memory"); }) + + +#define lll_mutex_islocked(futex) \ +  (futex != LLL_MUTEX_LOCK_INITIALIZER) + + +/* We have a separate internal lock implementation which is not tied +   to binary compatibility.  */ + +/* Type for lock object.  */ +typedef int lll_lock_t; + +/* Initializers for lock.  */ +#define LLL_LOCK_INITIALIZER		(0) +#define LLL_LOCK_INITIALIZER_LOCKED	(1) + + +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + + +/* The states of a lock are: +    0  -  untaken +    1  -  taken by one user +    2  -  taken by more users */ + + +#if defined NOT_IN_libc || defined UP +# define lll_trylock(futex) lll_mutex_trylock (futex) +# define lll_lock(futex) lll_mutex_lock (futex) +# define lll_unlock(futex) lll_mutex_unlock (futex) +#else +/* Special versions of the macros for use in libc itself.  They avoid +   the lock prefix when the thread library is not used. + +   The code sequence to avoid unnecessary lock prefixes is what the AMD +   guys suggested.  If you do not like it, bring it up with AMD. + +   XXX In future we might even want to avoid it on UP machines.  */ + +# define lll_trylock(futex) \ +  ({ unsigned char ret;							      \ +     __asm__ __volatile ("cmpl $0, __libc_multiple_threads(%%rip)\n\t"	      \ +		       "je 0f\n\t"					      \ +		       "lock; cmpxchgl %2, %1\n\t"			      \ +		       "jmp 1f\n"					      \ +		       "0:\tcmpxchgl %2, %1\n\t"			      \ +		       "1:setne %0"					      \ +		       : "=a" (ret), "=m" (futex)			      \ +		       : "r" (LLL_MUTEX_LOCK_INITIALIZER_LOCKED), "m" (futex),\ +			 "0" (LLL_MUTEX_LOCK_INITIALIZER)		      \ +		       : "memory");					      \ +     ret; }) + + +# define lll_lock(futex) \ +  (void) ({ int ignore1, ignore2, ignore3;				      \ +	    __asm__ __volatile ("cmpl $0, __libc_multiple_threads(%%rip)\n\t"   \ +			      "je 0f\n\t"				      \ +			      "lock; cmpxchgl %0, %2\n\t"		      \ +			      "jnz 1f\n\t"				      \ +			      "jmp 2f\n"				      \ +			      "0:\tcmpxchgl %0, %2\n\t"			      \ +			      "jnz 1f\n\t"				      \ +			      ".subsection 1\n"				      \ +			      "1:\tleaq %2, %%rdi\n\t"			      \ +			      "subq $128, %%rsp\n\t"			      \ +			      "callq __lll_mutex_lock_wait\n\t"		      \ +			      "addq $128, %%rsp\n\t"			      \ +			      "jmp 2f\n\t"				      \ +			      ".previous\n"				      \ +			      "2:"					      \ +			      : "=S" (ignore1), "=&D" (ignore2), "=m" (futex),\ +				"=a" (ignore3)				      \ +			      : "0" (1), "m" (futex), "3" (0)		      \ +			      : "cx", "r11", "cc", "memory"); }) + + +# define lll_unlock(futex) \ +  (void) ({ int ignore;							      \ +            __asm__ __volatile ("cmpl $0, __libc_multiple_threads(%%rip)\n\t"   \ +			      "je 0f\n\t"				      \ +			      "lock; decl %0\n\t"			      \ +			      "jne 1f\n\t"				      \ +			      "jmp 2f\n"				      \ +			      "0:\tdecl %0\n\t"				      \ +			      "jne 1f\n\t"				      \ +			      ".subsection 1\n"				      \ +			      "1:\tleaq %0, %%rdi\n\t"			      \ +			      "subq $128, %%rsp\n\t"			      \ +			      "callq __lll_mutex_unlock_wake\n\t"	      \ +			      "addq $128, %%rsp\n\t"			      \ +			      "jmp 2f\n\t"				      \ +			      ".previous\n"				      \ +			      "2:"					      \ +			      : "=m" (futex), "=&D" (ignore)		      \ +			      : "m" (futex)				      \ +			      : "ax", "cx", "r11", "cc", "memory"); }) +#endif + + +#define lll_islocked(futex) \ +  (futex != LLL_MUTEX_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; }) + + +/* Conditional variable handling.  */ + +extern void __lll_cond_wait (pthread_cond_t *cond) attribute_hidden; +extern int __lll_cond_timedwait (pthread_cond_t *cond, +				 const struct timespec *abstime) +     attribute_hidden; +extern void __lll_cond_wake (pthread_cond_t *cond) attribute_hidden; +extern void __lll_cond_broadcast (pthread_cond_t *cond) attribute_hidden; + + +#define lll_cond_wait(cond) \ +  __lll_cond_wait (cond) +#define lll_cond_timedwait(cond, abstime) \ +  __lll_cond_timedwait (cond, abstime) +#define lll_cond_wake(cond) \ +  __lll_cond_wake (cond) +#define lll_cond_broadcast(cond) \ +  __lll_cond_broadcast (cond) + + +#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..4b434632e --- /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 <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/not-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/not-cancel.h new file mode 100644 index 000000000..acf1a617e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/not-cancel.h @@ -0,0 +1 @@ +#include "../i386/not-cancel.h" 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..c20ef73e7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pt-vfork.S @@ -0,0 +1,31 @@ +/* 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.  */ + +#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..f6e15a2d7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_barrier_wait.S @@ -0,0 +1,159 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 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 <lowlevelbarrier.h> + +#define FUTEX_WAIT	0 +#define FUTEX_WAKE	1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + +	.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 +	xorl	%esi, %esi +#else +	movl	$FUTEX_WAIT, %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 +	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:	addq	$MUTEX, %rdi +	callq	__lll_mutex_lock_wait +	subq	$MUTEX, %rdi +	jmp	2b + +4:	addq	$MUTEX, %rdi +	callq	__lll_mutex_unlock_wake +	jmp	5b + +6:	addq	$MUTEX, %rdi +	callq	__lll_mutex_unlock_wake +	subq	$MUTEX, %rdi +	jmp	7b + +9:	addq	$MUTEX, %rdi +	callq	__lll_mutex_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..d8ebdfab8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S @@ -0,0 +1,136 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 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 <lowlevelcond.h> +#include <bits/kernel-features.h> + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 +#define FUTEX_REQUEUE		3 +#define FUTEX_CMP_REQUEUE	4 + +#define EINVAL			22 + + +	.text + +	/* int pthread_cond_broadcast (pthread_cond_t *cond) */ +	.globl	__pthread_cond_broadcast +	.type	__pthread_cond_broadcast, @function +	.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 + +	/* Wake up all threads.  */ +	movl	$FUTEX_CMP_REQUEUE, %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 +	jae	9f + +10:	xorl	%eax, %eax +	retq + +	.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 +	callq	__lll_mutex_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 +	callq	__lll_mutex_unlock_wake +	jmp	6b + +	/* Unlock in loop requires wakeup.  */ +7:	addq	$cond_lock-cond_futex, %rdi +	callq	__lll_mutex_unlock_wake +	subq	$cond_lock-cond_futex, %rdi +	jmp	8b + +9:	/* The futex requeue functionality is not available.  */ +	movl	$0x7fffffff, %edx +	movl	$FUTEX_WAKE, %esi +	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..c7cc3ddd8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_signal.S @@ -0,0 +1,101 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 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 <lowlevelcond.h> +#include <bits/kernel-features.h> + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 +#define FUTEX_REQUEUE		3 + +#define EINVAL			22 + + +	.text + +	/* int pthread_cond_signal (pthread_cond_t *cond) */ +	.globl	__pthread_cond_signal +	.type	__pthread_cond_signal, @function +	.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.  */ +	movl	$FUTEX_WAKE, %esi +	movl	$SYS_futex, %eax +	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 +	callq	__lll_mutex_lock_wait +#if cond_lock != 0 +	subq	$cond_lock, %rdi +#endif +	jmp	2b + +	/* Unlock in loop requires wakeup.  */ +5: +	movq	%r8, %rdi +	callq	__lll_mutex_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..f0dcdb750 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S @@ -0,0 +1,468 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 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 <lowlevelcond.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + +/* 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 +	.align	16 +__pthread_cond_timedwait: +.LSTARTCODE: +	pushq	%r12 +.Lpush_r12: +	pushq	%r13 +.Lpush_r13: +	pushq	%r14 +.Lpush_r14: +#define FRAME_SIZE 80 +	subq	$FRAME_SIZE, %rsp +.Lsubq: + +	cmpq	$1000000000, 8(%rdx) +	movl	$EINVAL, %eax +	jae	18f + +	/* Stack frame: + +	   rsp + 80 +	            +--------------------------+ +	   rsp + 48 | cleanup buffer           | +	            +--------------------------+ +	   rsp + 40 | old wake_seq value       | +	            +--------------------------+ +	   rsp + 24 | timeout 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) + +	/* Get internal lock.  */ +22:	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	16f + +	movq	8(%rsp), %rdi +	incq	total_seq(%rdi) +	incl	cond_futex(%rdi) +	addl	$(1 << clock_bits), cond_nwaiters(%rdi) + +	/* Install cancellation handler.  */ +#ifdef __PIC__ +	leaq	__condvar_cleanup(%rip), %rsi +#else +	leaq	__condvar_cleanup, %rsi +#endif +	leaq	48(%rsp), %rdi +	movq	%rsp, %rdx +	callq	__pthread_cleanup_push + +	/* Get and store current wakeup_seq value.  */ +	movq	8(%rsp), %rdi +	movq	wakeup_seq(%rdi), %r9 +	movl	broadcast_seq(%rdi), %edx +	movq	%r9, 40(%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 << clock_bits) - 1), %edi +	/* Only clocks 0 and 1 are allowed so far.  Both are handled in the +	   kernel.  */ +	leaq	24(%rsp), %rsi +	movl	$__NR_clock_gettime, %eax +	syscall +# ifndef __ASSUME_POSIX_TIMERS +	cmpq	$-ENOSYS, %rax +	je	19f +# endif + +	/* Compute relative timeout.  */ +	movq	(%r13), %rcx +	movq	8(%r13), %rdx +	subq	24(%rsp), %rcx +	subq	32(%rsp), %rdx +#else +	leaq	24(%rsp), %rdi +	xorl	%esi, %esi +	movq	$VSYSCALL_ADDR_vgettimeofday, %rax +	callq	*%rax + +	/* Compute relative timeout.  */ +	movq	32(%rsp), %rax +	movl	$1000, %edx +	mul	%rdx		/* Milli seconds to nano seconds.  */ +	movq	(%r13), %rcx +	movq	8(%r13), %rdx +	subq	24(%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, 24(%rsp) +	movq	%rdx, 32(%rsp) + +	movl	cond_futex(%rdi), %r12d + +	/* Unlock.  */ +	LOCK +#if cond_lock == 0 +	decl	(%rdi) +#else +	decl	cond_lock(%rdi) +#endif +	jne	3f + +4:	callq	__pthread_enable_asynccancel +	movl	%eax, (%rsp) + +	leaq	24(%rsp), %r10 +#if FUTEX_WAIT == 0 +	xorl	%esi, %esi +#else +	movl	$FUTEX_WAIT, %esi +#endif +	movq	%r12, %rdx +	addq	$cond_futex, %rdi +	movl	$SYS_futex, %eax +	syscall +	movq	%rax, %r14 + +	movl	(%rsp), %edi +	callq	__pthread_disable_asynccancel + +	/* 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	23f + +	cmpq	40(%rsp), %r9 +	jbe	15f + +	cmpq	%rax, %r9 +	ja	9f + +15:	cmpq	$-ETIMEDOUT, %r14 +	jne	8b + +13:	incq	wakeup_seq(%rdi) +	incl	cond_futex(%rdi) +	movl	$ETIMEDOUT, %r14d +	jmp	14f + +23:	xorq	%r14, %r14 +	jmp	24f + +9:	xorq	%r14, %r14 +14:	incq	woken_seq(%rdi) + +24:	subl	$(1 << clock_bits), cond_nwaiters(%rdi) + +	/* Wake up a thread which wants to destroy the condvar object.  */ +	cmpq	$0xffffffffffffffff, total_seq(%rdi) +	jne	25f +	movl	cond_nwaiters(%rdi), %eax +	andl	$~((1 << clock_bits) - 1), %eax +	jne	25f + +	addq	$cond_nwaiters, %rdi +	movl	$SYS_futex, %eax +	movl	$FUTEX_WAKE, %esi +	movl	$1, %edx +	syscall +	subq	$cond_nwaiters, %rdi + +25:	LOCK +#if cond_lock == 0 +	decl	(%rdi) +#else +	decl	cond_lock(%rdi) +#endif +	jne	10f + +	/* Remove cancellation handler.  */ +11:	movq	48+CLEANUP_PREV(%rsp), %rdx +	movq	%rdx, %fs:CLEANUP + +	movq	16(%rsp), %rdi +	callq	__pthread_mutex_cond_lock + +	testq	%rax, %rax +	cmoveq	%r14, %rax + +18:	addq	$FRAME_SIZE, %rsp +.Laddq: +	popq	%r14 +.Lpop_r14: +	popq	%r13 +.Lpop_r13: +	popq	%r12 +.Lpop_r12: + +	retq + +	/* Initial locking failed.  */ +1: +.LSbl1: +#if cond_lock != 0 +	addq	$cond_lock, %rdi +#endif +	callq	__lll_mutex_lock_wait +	jmp	2b + +	/* Unlock in loop requires wakeup.  */ +3: +#if cond_lock != 0 +	addq	$cond_lock, %rdi +#endif +	callq	__lll_mutex_unlock_wake +	jmp	4b + +	/* Locking in loop failed.  */ +5: +#if cond_lock != 0 +	addq	$cond_lock, %rdi +#endif +	callq	__lll_mutex_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 +	callq	__lll_mutex_unlock_wake +	jmp	11b + +	/* The initial unlocking of the mutex failed.  */ +16:	movq	8(%rsp), %rdi +	movq	%rax, (%rsp) +	LOCK +#if cond_lock == 0 +	decl	(%rdi) +#else +	decl	cond_lock(%rdi) +#endif +	jne	17f + +#if cond_lock != 0 +	addq	$cond_lock, %rdi +#endif +	callq	__lll_mutex_unlock_wake + +17:	movq	(%rsp), %rax +	jmp	18b + +#if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS +	/* clock_gettime not available.  */ +19:	leaq	24(%rsp), %rdi +	xorl	%esi, %esi +	movq	$VSYSCALL_ADDR_vgettimeofday, %rax +	callq	*%rax + +	/* Compute relative timeout.  */ +	movq	32(%rsp), %rax +	movl	$1000, %edx +	mul	%rdx		/* Milli seconds to nano seconds.  */ +	movq	(%r13), %rcx +	movq	8(%r13), %rdx +	subq	24(%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 +.LENDCODE: +	.size	__pthread_cond_timedwait, .-__pthread_cond_timedwait +weak_alias(__pthread_cond_timedwait, pthread_cond_timedwait) + + +	.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	"zR"				# NUL-terminated augmentation +						# string. +#else +	.ascii	"\0"				# NUL-terminated augmentation +						# string. +#endif +	.uleb128 1				# Code alignment factor. +	.sleb128 -8				# Data alignment factor. +	.byte	16				# Return address register +						# column. +#ifdef SHARED +	.uleb128 1				# Augmentation value length. +	.byte	0x1b				# Encoding: DW_EH_PE_pcrel +						# + DW_EH_PE_sdata4. +#endif +	.byte 0x0c				# DW_CFA_def_cfa +	.uleb128 7 +	.uleb128 8 +	.byte	0x90				# DW_CFA_offset, column 0x8 +	.uleb128 1 +	.align 8 +.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. +#ifdef SHARED +	.uleb128 0				# No augmentation data. +#endif +	.byte	0x40+.Lpush_r12-.LSTARTCODE	# DW_CFA_advance_loc+N +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 16 +	.byte	0x8c				# DW_CFA_offset %r12 +	.uleb128 2 +	.byte	0x40+.Lpush_r13-.Lpush_r12	# DW_CFA_advance_loc+N +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 24 +	.byte	0x8d				# DW_CFA_offset %r13 +	.uleb128 3 +	.byte	0x40+.Lpush_r14-.Lpush_r13	# DW_CFA_advance_loc+N +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 32 +	.byte	0x84				# DW_CFA_offset %r14 +	.uleb128 4 +	.byte	0x40+.Lsubq-.Lpush_r14		# DW_CFA_advance_loc+N +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 32+FRAME_SIZE +	.byte	3				# DW_CFA_advance_loc2 +	.2byte	.Laddq-.Lsubq +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 32 +	.byte	0x40+.Lpop_r14-.Laddq		# DW_CFA_advance_loc+N +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 24 +	.byte	0xce				# DW_CFA_restore %r14 +	.byte	0x40+.Lpop_r13-.Lpop_r14	# DW_CFA_advance_loc+N +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 16 +	.byte	0xcd				# DW_CFA_restore %r13 +	.byte	0x40+.Lpop_r12-.Lpop_r13	# DW_CFA_advance_loc+N +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 8 +	.byte	0xcc				# DW_CFA_restore %r12 +	.byte	0x40+.LSbl1-.Lpop_r12		# DW_CFA_advance_loc+N +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 32+FRAME_SIZE +	.byte	0x8c				# DW_CFA_offset %r12 +	.uleb128 2 +	.byte	0x8d				# DW_CFA_offset %r13 +	.uleb128 3 +	.byte	0x84				# DW_CFA_offset %r14 +	.uleb128 4 +	.align	8 +.LENDFDE: 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..544118eb7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S @@ -0,0 +1,420 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 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 <lowlevelcond.h> +#include <tcb-offsets.h> + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + + +	.text + +	.align	16 +	.type	__condvar_cleanup, @function +	.globl	__condvar_cleanup +	.hidden	__condvar_cleanup +__condvar_cleanup: +	pushq	%r12 + +	/* Get internal lock.  */ +	movq	%rdi, %r8 +	movq	8(%rdi), %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 +	callq	__lll_mutex_lock_wait +#if cond_lock != 0 +	subq	$cond_lock, %rdi +#endif + +1:	movl	broadcast_seq(%rdi), %edx +	cmpl	4(%r8), %edx +	jne	3f + +	incq	wakeup_seq(%rdi) +	incq	woken_seq(%rdi) +	incl	cond_futex(%rdi) + +3:	subl	$(1 << clock_bits), 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 << clock_bits) - 1), %eax +	jne	4f + +	addq	$cond_nwaiters, %rdi +	movl	$SYS_futex, %eax +	movl	$FUTEX_WAKE, %esi +	movl	$1, %edx +	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 +	callq	__lll_mutex_unlock_wake + +	/* Wake up all waiters to make sure no signal gets lost.  */ +2:	testq	%r12, %r12 +	jnz	5f +	addq	$cond_futex, %rdi +	movl	$FUTEX_WAKE, %esi +	movl	$0x7fffffff, %edx +	movl	$SYS_futex, %eax +	syscall + +5:	movq	16(%r8), %rdi +	callq	__pthread_mutex_cond_lock + +	popq	%r12 + +	retq +	.size	__condvar_cleanup, .-__condvar_cleanup + + +/* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)  */ +	.globl	__pthread_cond_wait +	.type	__pthread_cond_wait, @function +	.align	16 +__pthread_cond_wait: +.LSTARTCODE: +	pushq	%r12 +.Lpush_r12: +#define FRAME_SIZE 64 +	subq	$FRAME_SIZE, %rsp +.Lsubq: +	/* Stack frame: + +	   rsp + 64 +	            +--------------------------+ +	   rsp + 32 | cleanup buffer           | +		    +--------------------------+ +	   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 << clock_bits), cond_nwaiters(%rdi) + +	/* Install cancellation handler.  */ +#ifdef __PIC__ +	leaq	__condvar_cleanup(%rip), %rsi +#else +	leaq	__condvar_cleanup, %rsi +#endif +	leaq	32(%rsp), %rdi +	movq	%rsp, %rdx +	callq	__pthread_cleanup_push + +	/* 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), %r12d +	LOCK +#if cond_lock == 0 +	decl	(%rdi) +#else +	decl	cond_lock(%rdi) +#endif +	jne	3f + +4:	callq	__pthread_enable_asynccancel +	movl	%eax, (%rsp) + +	movq	8(%rsp), %rdi +	xorq	%r10, %r10 +	movq	%r12, %rdx +	addq	$cond_futex-cond_lock, %rdi +	movl	$SYS_futex, %eax +#if FUTEX_WAIT == 0 +	xorl	%esi, %esi +#else +	movl	$FUTEX_WAIT, %esi +#endif +	syscall + +	movl	(%rsp), %edi +	callq	__pthread_disable_asynccancel + +	/* 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 << clock_bits), 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 << clock_bits) - 1), %eax +	jne	17f + +	addq	$cond_nwaiters, %rdi +	movl	$SYS_futex, %eax +	movl	$FUTEX_WAKE, %esi +	movl	$1, %edx +	syscall +	subq	$cond_nwaiters, %rdi + +17:	LOCK +#if cond_lock == 0 +	decl	(%rdi) +#else +	decl	cond_lock(%rdi) +#endif +	jne	10f + +	/* Remove cancellation handler.  */ +11:	movq	32+CLEANUP_PREV(%rsp), %rdx +	movq	%rdx, %fs:CLEANUP + +	movq	16(%rsp), %rdi +	callq	__pthread_mutex_cond_lock +14:	addq	$FRAME_SIZE, %rsp +.Laddq: + +	popq	%r12 +.Lpop_r12: + +	/* We return the result of the mutex_lock operation.  */ +	retq + +	/* Initial locking failed.  */ +1: +.LSbl1: +#if cond_lock != 0 +	addq	$cond_lock, %rdi +#endif +	callq	__lll_mutex_lock_wait +	jmp	2b + +	/* Unlock in loop requires wakeup.  */ +3: +#if cond_lock != 0 +	addq	$cond_lock, %rdi +#endif +	callq	__lll_mutex_unlock_wake +	jmp	4b + +	/* Locking in loop failed.  */ +5: +#if cond_lock != 0 +	addq	$cond_lock, %rdi +#endif +	callq	__lll_mutex_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 +	callq	__lll_mutex_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 +	jne	13f + +#if cond_lock != 0 +	addq	$cond_lock, %rdi +#endif +	callq	__lll_mutex_unlock_wake + +13:	movq	%r10, %rax +	jmp	14b +.LENDCODE: +	.size	__pthread_cond_wait, .-__pthread_cond_wait +weak_alias(__pthread_cond_wait, pthread_cond_wait) + + +	.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	"zR"				# NUL-terminated augmentation +						# string. +#else +	.ascii	"\0"				# NUL-terminated augmentation +						# string. +#endif +	.uleb128 1				# Code alignment factor. +	.sleb128 -8				# Data alignment factor. +	.byte	16				# Return address register +						# column. +#ifdef SHARED +	.uleb128 1				# Augmentation value length. +	.byte	0x1b				# Encoding: DW_EH_PE_pcrel +						# + DW_EH_PE_sdata4. +#endif +	.byte 0x0c				# DW_CFA_def_cfa +	.uleb128 7 +	.uleb128 8 +	.byte	0x90				# DW_CFA_offset, column 0x8 +	.uleb128 1 +	.align 8 +.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. +#ifdef SHARED +	.uleb128 0				# No augmentation data. +#endif +	.byte	0x40+.Lpush_r12-.LSTARTCODE	# DW_CFA_advance_loc+N +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 16 +	.byte	0x8c				# DW_CFA_offset %r12 +	.uleb128 2 +	.byte	0x40+.Lsubq-.Lpush_r12		# DW_CFA_advance_loc+N +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 16+FRAME_SIZE +	.byte	3				# DW_CFA_advance_loc2 +	.2byte	.Laddq-.Lsubq +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 16 +	.byte	0x40+.Lpop_r12-.Laddq		# DW_CFA_advance_loc+N +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 8 +	.byte	0xcc				# DW_CFA_restore %r12 +	.byte	0x40+.LSbl1-.Lpop_r12		# DW_CFA_advance_loc+N +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 80 +	.byte	0x8c				# DW_CFA_offset %r12 +	.uleb128 2 +	.align	8 +.LENDFDE: 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..d8bfa26c6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S @@ -0,0 +1,259 @@ +/* Copyright (C) 2002, 2003, 2005 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> + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + +#define FUTEX_WAIT  0 +#define FUTEX_WAKE	1 + +	.comm	__fork_generation, 4, 4 + +	.text + + +	.globl	__pthread_once +	.type	__pthread_once,@function +	.align	16 +__pthread_once: +.LSTARTCODE: +	testl	$2, (%rdi) +	jz	1f +	xorl	%eax, %eax +	retq + +	/* Preserve the function pointer.  */ +1:	pushq	%rsi +.Lpush_rsi: +	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.  */ +#if FUTEX_WAIT == 0 +	xorl	%esi, %esi +#else +	movl	$FUTEX_WAIT, %esi +#endif +	movl	$SYS_futex, %eax +	syscall +	jmp	6b + +	/* Preserve the pointer to the control variable.  */ +3:	pushq	%rdi +.Lpush_rdi: + +.LcleanupSTART: +	callq	*8(%rsp) +.LcleanupEND: + +	/* Get the control variable address back.  */ +	popq	%rdi +.Lpop_rdi: + +	/* Sucessful run of the initializer.  Signal that we are done.  */ +	LOCK +	incl	(%rdi) + +	/* Wake up all other threads.  */ +	movl	$0x7fffffff, %edx +	movl	$FUTEX_WAKE, %esi +	movl	$SYS_futex, %eax +	syscall + +4:	addq	$8, %rsp +.Ladd: +	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: +	movq	(%rsp), %rdi +	movq	%rax, %r8 +	movl	$0, (%rdi) + +	movl	$0x7fffffff, %edx +	movl	$FUTEX_WAKE, %esi +	movl	$SYS_futex, %eax +	syscall + +	movq	%r8, %rdi +.LcallUR: +	call	_Unwind_Resume@PLT +	hlt +.LENDCODE: +	.size	clear_once_control,.-clear_once_control + + +	.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 clear_once_control-.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 -8				# Data alignment factor. +	.byte	16				# 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 10				# Augmentation value length. +	.byte	0x0				# Personality: absolute +	.quad	__gcc_personality_v0 +	.byte	0x0				# LSDA Encoding: absolute +#endif +	.byte 0x0c				# DW_CFA_def_cfa +	.uleb128 7 +	.uleb128 8 +	.byte	0x90				# DW_CFA_offset, column 0x10 +	.uleb128 1 +	.align 8 +.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. +	.long	.LENDCODE-.LSTARTCODE		# Length of the code. +	.uleb128 4				# Augmentation size +	.long	.LexceptSTART-. +#else +	.quad	.LSTARTCODE			# Start address of the code. +	.quad	.LENDCODE-.LSTARTCODE		# Length of the code. +	.uleb128 8				# Augmentation size +	.quad	.LexceptSTART +#endif +	.byte	4				# DW_CFA_advance_loc4 +	.long	.Lpush_rsi-.LSTARTCODE +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 16 +	.byte	4				# DW_CFA_advance_loc4 +	.long	.Lpush_rdi-.Lpush_rsi +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 24 +	.byte	4				# DW_CFA_advance_loc4 +	.long	.Lpop_rdi-.Lpush_rdi +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 16 +	.byte	4				# DW_CFA_advance_loc4 +	.long	.Ladd-.Lpop_rdi +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 8 +	.byte	4				# DW_CFA_advance_loc4 +	.long	clear_once_control-.Ladd +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 24 +#if 0 +	.byte	4				# DW_CFA_advance_loc4 +	.long	.Lpop_rdi2-clear_once_control +	.byte	14				# DW_CFA_def_cfa_offset +	.uleb128 16 +#endif +	.align	8 +.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	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..d7543572a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_rdlock.S @@ -0,0 +1,177 @@ +/* Copyright (C) 2002, 2003, 2005 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 <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> + + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + +	.text + +	.globl	__pthread_rwlock_rdlock +	.type	__pthread_rwlock_rdlock,@function +	.align	16 +__pthread_rwlock_rdlock: +	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:	addq	$READERS_WAKEUP, %rdi +#if FUTEX_WAIT == 0 +	xorl	%esi, %esi +#else +	movl	$FUTEX_WAIT, %esi +#endif +	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: +#if MUTEX != 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_mutex_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: +#if MUTEX != 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_mutex_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: +#if MUTEX != 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_mutex_unlock_wake +#if MUTEX != 0 +	subq	$MUTEX, %rdi +#endif +	jmp	11b + +12: +#if MUTEX == 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_mutex_lock_wait +#if MUTEX != 0 +	subq	$MUTEX, %rdi +#endif +	jmp	13b +	.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..f044842e0 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedrdlock.S @@ -0,0 +1,220 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 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 <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> + + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + +/* For the calculation see asm/vsyscall.h.  */ +#define VSYSCALL_ADDR_vgettimeofday	0xffffffffff600000 + + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + +	.text + +	.globl	pthread_rwlock_timedrdlock +	.type	pthread_rwlock_timedrdlock,@function +	.align	16 +pthread_rwlock_timedrdlock: +	pushq	%r12 +	pushq	%r13 +	pushq	%r14 +	subq	$16, %rsp + +	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), %r14d + +	/* Unlock.  */ +	LOCK +#if MUTEX == 0 +	decl	(%r12) +#else +	decl	MUTEX(%r12) +#endif +	jne	10f + +	/* Get current time.  */ +11:	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) + +#if FUTEX_WAIT == 0 +	xorl	%esi, %esi +#else +	movl	$FUTEX_WAIT, %esi +#endif +	movq	%rsp, %r10 +	movl	%r14d, %edx +	leaq	READERS_WAKEUP(%r12), %rdi +	movl	$SYS_futex, %eax +	syscall +	movq	%rax, %rdx +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 + +	addq	$16, %rsp +	popq	%r14 +	popq	%r13 +	popq	%r12 +	retq + +1: +#if MUTEX != 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_mutex_lock_wait +	jmp	2b + +14:	cmpl	%fs:TID, %eax +	jne	3b +	movl	$EDEADLK, %edx +	jmp	9b + +6: +#if MUTEX == 0 +	movq	%r12, %rdi +#else +	leal	MUTEX(%r12), %rdi +#endif +	callq	__lll_mutex_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: +#if MUTEX == 0 +	movq	%r12, %rdi +#else +	leaq	MUTEX(%r12), %rdi +#endif +	callq	__lll_mutex_unlock_wake +	jmp	11b + +12: +#if MUTEX == 0 +	movq	%r12, %rdi +#else +	leaq	MUTEX(%r12), %rdi +#endif +	callq	__lll_mutex_lock_wait +	jmp	13b + +16:	movq	$-ETIMEDOUT, %rdx +	jmp	17b + +19:	movl	$EINVAL, %edx +	jmp	9b +	.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..b479da727 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_timedwrlock.S @@ -0,0 +1,211 @@ +/* Copyright (C) 2002, 2003, 2005 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 <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> + + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + +/* For the calculation see asm/vsyscall.h.  */ +#define VSYSCALL_ADDR_vgettimeofday	0xffffffffff600000 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + +	.text + +	.globl	pthread_rwlock_timedwrlock +	.type	pthread_rwlock_timedwrlock,@function +	.align	16 +pthread_rwlock_timedwrlock: +	pushq	%r12 +	pushq	%r13 +	pushq	%r14 +	subq	$16, %rsp + +	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), %r14d + +	LOCK +#if MUTEX == 0 +	decl	(%r12) +#else +	decl	MUTEX(%r12) +#endif +	jne	10f + +	/* Get current time.  */ +11:	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) + +#if FUTEX_WAIT == 0 +	xorl	%esi, %esi +#else +	movl	$FUTEX_WAIT, %esi +#endif +	movq	%rsp, %r10 +	movl	%r14d, %edx +	leaq	WRITERS_WAKEUP(%r12), %rdi +	movl	$SYS_futex, %eax +	syscall +	movq	%rax, %rdx +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 + +	addq	$16, %rsp +	popq	%r14 +	popq	%r13 +	popq	%r12 +	retq + +1: +#if MUTEX != 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_mutex_lock_wait +	jmp	2b + +14:	cmpl	%fs:TID, %eax +	jne	3b +20:	movl	$EDEADLK, %edx +	jmp	9b + +6: +#if MUTEX == 0 +	movq	%r12, %rdi +#else +	leal	MUTEX(%r12), %rdi +#endif +	callq	__lll_mutex_unlock_wake +	jmp	7b + +	/* Overflow.  */ +4:	decl	WRITERS_QUEUED(%r12) +	movl	$EAGAIN, %edx +	jmp	9b + +10: +#if MUTEX == 0 +	movq	%r12, %rdi +#else +	leaq	MUTEX(%r12), %rdi +#endif +	callq	__lll_mutex_unlock_wake +	jmp	11b + +12: +#if MUTEX == 0 +	movq	%r12, %rdi +#else +	leaq	MUTEX(%r12), %rdi +#endif +	callq	__lll_mutex_lock_wait +	jmp	13b + +16:	movq	$-ETIMEDOUT, %rdx +	jmp	17b + +19:	movl	$EINVAL, %edx +	jmp	9b +	.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..a0f75226a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_unlock.S @@ -0,0 +1,129 @@ +/* Copyright (C) 2002, 2003, 2005 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 <lowlevelrwlock.h> + + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + +	.text + +	.globl	__pthread_rwlock_unlock +	.type	__pthread_rwlock_unlock,@function +	.align	16 +__pthread_rwlock_unlock: +	/* 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, %esi +	leaq	WRITERS_WAKEUP(%rdi), %r10 +	movq	%rsi, %rdx +	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:	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: +#if MUTEX != 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_mutex_lock_wait +#if MUTEX != 0 +	subq	$MUTEX, %rdi +#endif +	jmp	2b + +3: +#if MUTEX != 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_mutex_unlock_wake +	jmp	4b + +7: +#if MUTEX != 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_mutex_unlock_wake +	jmp	8b + +	.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..39b54dc6b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_rwlock_wrlock.S @@ -0,0 +1,165 @@ +/* Copyright (C) 2002, 2003, 2005 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 <lowlevelrwlock.h> +#include <pthread-errnos.h> +#include <tcb-offsets.h> + + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 + +#ifndef UP +# define LOCK lock +#else +# define LOCK +#endif + + +	.text + +	.globl	__pthread_rwlock_wrlock +	.type	__pthread_rwlock_wrlock,@function +	.align	16 +__pthread_rwlock_wrlock: +	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:	addq	$WRITERS_WAKEUP, %rdi +#if FUTEX_WAIT == 0 +	xorl	%esi, %esi +#else +	movl	$FUTEX_WAIT, %esi +#endif +	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: +#if MUTEX != 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_mutex_lock_wait +#if MUTEX != 0 +	subq	$MUTEX, %rdi +#endif +	jmp	2b + +14:	cmpl	%fs:TID, %eax +	jne	3b +	movl	$EDEADLK, %edx +	jmp	9b + +6: +#if MUTEX != 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_mutex_unlock_wake +	jmp	7b + +4:	decl	WRITERS_QUEUED(%rdi) +	movl	$EAGAIN, %edx +	jmp	9b + +10: +#if MUTEX != 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_mutex_unlock_wake +#if MUTEX != 0 +	subq	$MUTEX, %rdi +#endif +	jmp	11b + +12: +#if MUTEX != 0 +	addq	$MUTEX, %rdi +#endif +	callq	__lll_mutex_lock_wait +#if MUTEX != 0 +	subq	$MUTEX, %rdi +#endif +	jmp	13b +	.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..5c8a858ad --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_post.S @@ -0,0 +1,64 @@ +/* Copyright (C) 2002, 2003, 2005 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> + +#ifndef UP +# define LOCK lock +#else +# define +#endif + +#define FUTEX_WAKE		1 + + +	.text + +	.globl	sem_post +	.type	sem_post,@function +	.align	16 +sem_post: +	movl	$1, %edx +	LOCK +	xaddl	%edx, (%rdi) + +	movl	$SYS_futex, %eax +	movl	$FUTEX_WAKE, %esi +	incl	%edx +	syscall + +	testq	%rax, %rax +	js	1f + +	xorl	%eax, %eax +	retq + +1: +#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 +	.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..64e168099 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S @@ -0,0 +1,174 @@ +/* Copyright (C) 2002, 2003, 2005 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 <tcb-offsets.h> +#include <tls.h> + +#ifndef UP +# define LOCK lock +#else +# define +#endif + +/* For the calculation see asm/vsyscall.h.  */ +#define VSYSCALL_ADDR_vgettimeofday	0xffffffffff600000 + + +	.text + +	.globl	sem_timedwait +	.type	sem_timedwait,@function +	.align	16 +	cfi_startproc +sem_timedwait: +	/* First check for cancellation.  */ +	movl	%fs:CANCELHANDLING, %eax +	andl	$0xfffffff9, %eax +	cmpl	$8, %eax +	je	11f + +	movl	(%rdi), %eax +2:	testl	%eax, %eax +	je	1f + +	leaq	-1(%rax), %rdx +	LOCK +	cmpxchgl %edx, (%rdi) +	jne	2b + +	xorl	%eax, %eax +	retq + +	/* Check whether the timeout value is valid.  */ +1:	pushq	%r12 +	cfi_adjust_cfa_offset(8) +	pushq	%r13 +	cfi_adjust_cfa_offset(8) +	pushq	%r14 +	cfi_adjust_cfa_offset(8) +	subq	$24, %rsp +	cfi_adjust_cfa_offset(24) + +	movq	%rdi, %r12 +	cfi_offset(12, -16)		/* %r12 */ +	movq	%rsi, %r13 +	cfi_offset(13, -24)		/* %r13 */ + +	/* Check for invalid nanosecond field.  */ +	cmpq	$1000000000, 8(%r13) +	movl	$EINVAL, %r14d +	cfi_offset(14, -24)		/* %r14 */ +	jae	6f + +7:	call	__pthread_enable_asynccancel +	movl	%eax, 16(%rsp) + +	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	6f		/* Time is already up.  */ + +	movq	%rdi, (%rsp)	/* Store relative timeout.  */ +	movq	%rsi, 8(%rsp) + +	movq	%rsp, %r10 +	movq	%r12, %rdi +	xorl	%esi, %esi +	movl	$SYS_futex, %eax +	xorl	%edx, %edx +	syscall +	movq	%rax, %r14 + +	movl	16(%rsp), %edi +	call	__pthread_disable_asynccancel + +	testq	%r14, %r14 +	je	9f +	cmpq	$-EWOULDBLOCK, %r14 +	jne	3f + +9:	movl	(%r12), %eax +8:	testl	%eax, %eax +	je	7b + +	leaq	-1(%rax), %rcx +	LOCK +	cmpxchgl %ecx, (%r12) +	jne	8b + +	xorl	%eax, %eax +10:	addq	$24, %rsp +	cfi_adjust_cfa_offset(-24) +	popq	%r14 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(14) +	popq	%r13 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(13) +	popq	%r12 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(12) +	retq + +	cfi_adjust_cfa_offset(48) +	cfi_offset(12, -16)		/* %r12 */ +	cfi_offset(13, -24)		/* %r13 */ +	cfi_offset(14, -32)		/* %r14 */ +3:	negq	%r14 +6: +#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	10b +	cfi_adjust_cfa_offset(-48) +	cfi_restore(14) +	cfi_restore(13) +	cfi_restore(12) + +11:	/* Canceled.  */ +	movq	$0xffffffffffffffff, %fs:RESULT +	LOCK +	orl	$0x10, %fs:CANCELHANDLING +	movq	%fs:CLEANUP_JMP_BUF, %rdi +	jmp	HIDDEN_JUMPTARGET (__pthread_unwind) +	cfi_endproc +	.size	sem_timedwait,.-sem_timedwait 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..08edc390c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_trywait.S @@ -0,0 +1,57 @@ +/* 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 <sysdep.h> +#include <pthread-errnos.h> + +#ifndef UP +# define LOCK lock +#else +# define +#endif + +	.text + +	.globl	sem_trywait +	.type	sem_trywait,@function +	.align	16 +sem_trywait: +	movl	(%rdi), %eax +2:	testl	%eax, %eax +	jz	1f + +	leaq	-1(%rax), %rdx +	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..c2f94d47f --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S @@ -0,0 +1,119 @@ +/* Copyright (C) 2002, 2003, 2005 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 <tcb-offsets.h> +#include <tls.h> + +#ifndef UP +# define LOCK lock +#else +# define +#endif + + +	.text + +	.globl	sem_wait +	.type	sem_wait,@function +	.align	16 +	cfi_startproc +sem_wait: +	/* First check for cancellation.  */ +	movl	%fs:CANCELHANDLING, %eax +	andl	$0xfffffff9, %eax +	cmpl	$8, %eax +	je	4f + +	pushq	%r12 +	cfi_adjust_cfa_offset(8) +	cfi_offset(12, -16) +	pushq	%r13 +	cfi_adjust_cfa_offset(8) +	movq	%rdi, %r13 +	cfi_offset(13, -24) + +3:	movl	(%r13), %eax +2:	testl	%eax, %eax +	je	1f + +	leaq	-1(%rax), %rdx +	LOCK +	cmpxchgl %edx, (%r13) +	jne	2b +	xorl	%eax, %eax + +	popq	%r13 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(13) +	popq	%r12 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(12) + +	retq + +	cfi_adjust_cfa_offset(16) +	cfi_offset(12, -16) +	cfi_offset(13, -24) +1:	call	__pthread_enable_asynccancel +	movl	%eax, %r8d + +	xorq	%r10, %r10 +	movl	$SYS_futex, %eax +	movq	%r13, %rdi +	movq	%r10, %rsi +	movq	%r10, %rdx +	syscall +	movq	%rax, %r12 + +	movl	%r8d, %edi +	call	__pthread_disable_asynccancel + +	testq	%r12, %r12 +	je	3b +	cmpq	$-EWOULDBLOCK, %r12 +	je	3b +	negq	%r12 +#if USE___THREAD +	movq	errno@gottpoff(%rip), %rdx +	movl	%r12d, %fs:(%rdx) +#else +	callq	__errno_location@plt +	movl	%r12d, (%rax) +#endif +	orl	$-1, %eax + +	popq	%r13 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(13) +	popq	%r12 +	cfi_adjust_cfa_offset(-8) +	cfi_restore(12) + +	retq + +4:	/* Canceled.  */ +	movq	$0xffffffffffffffff, %fs:RESULT +	LOCK +	orl	$0x10, %fs:CANCELHANDLING +	movq	%fs:CLEANUP_JMP_BUF, %rdi +	jmp	HIDDEN_JUMPTARGET (__pthread_unwind) +	cfi_endproc +	.size	sem_wait,.-sem_wait 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/sysdep.h b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sysdep.h new file mode 100644 index 000000000..fe92a8ab5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/x86_64/sysdep.h @@ -0,0 +1,259 @@ +/* Copyright (C) 2001-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 _LINUX_X86_64_SYSDEP_H +#define _LINUX_X86_64_SYSDEP_H 1 + +/* There is some commonality.  */ +#include <sys/syscall.h> +#include <sysdeps/i386/sysdep.h> + +#ifdef IS_IN_rtld +# include <dl-sysdep.h>		/* Defines RTLD_PRIVATE_ERRNO.  */ +#endif + +/* For Linux we can use the system call table in the header file +	/usr/include/asm/unistd.h +   of the kernel.  But these symbols do not follow the SYS_* syntax +   so we have to redefine the `SYS_ify' macro here.  */ +#undef SYS_ify +#define SYS_ify(syscall_name)	__NR_##syscall_name + +/* This is a kludge to make syscalls.list find these under the names +   pread and pwrite, since some kernel headers define those names +   and some define the *64 names for the same system calls.  */ +#if !defined __NR_pread && defined __NR_pread64 +# define __NR_pread __NR_pread64 +#endif +#if !defined __NR_pwrite && defined __NR_pwrite64 +# define __NR_pwrite __NR_pwrite64 +#endif + +/* This is to help the old kernel headers where __NR_semtimedop is not +   available.  */ +#ifndef __NR_semtimedop +# define __NR_semtimedop 220 +#endif + + +#ifdef __ASSEMBLER__ + +/* Linux uses a negative return value to indicate syscall errors, +   unlike most Unices, which use the condition codes' carry flag. + +   Since version 2.1 the return value of a system call might be +   negative even if the call succeeded.	 E.g., the `lseek' system call +   might return a large offset.	 Therefore we must not anymore test +   for < 0, but test for a real error by making sure the value in %eax +   is a real error number.  Linus said he will make sure the no syscall +   returns a value in -1 .. -4095 as a valid result so we can savely +   test with -4095.  */ + +/* We don't want the label for the error handle to be global when we define +   it here.  */ +# ifdef __PIC__ +#  define SYSCALL_ERROR_LABEL 0f +# else +#  define SYSCALL_ERROR_LABEL syscall_error +# endif + +# undef	PSEUDO +# define PSEUDO(name, syscall_name, args)				      \ +  .text;								      \ +  ENTRY (name)								      \ +    DO_CALL (syscall_name, args);					      \ +    cmpq $-4095, %rax;							      \ +    jae SYSCALL_ERROR_LABEL;						      \ +  L(pseudo_end): + +# undef	PSEUDO_END +# define PSEUDO_END(name)						      \ +  SYSCALL_ERROR_HANDLER							      \ +  END (name) + +# undef	PSEUDO_NOERRNO +# define PSEUDO_NOERRNO(name, syscall_name, args) \ +  .text;								      \ +  ENTRY (name)								      \ +    DO_CALL (syscall_name, args) + +# undef	PSEUDO_END_NOERRNO +# define PSEUDO_END_NOERRNO(name) \ +  END (name) + +# define ret_NOERRNO ret + +# undef	PSEUDO_ERRVAL +# define PSEUDO_ERRVAL(name, syscall_name, args) \ +  .text;								      \ +  ENTRY (name)								      \ +    DO_CALL (syscall_name, args);					      \ +    negq %rax + +# undef	PSEUDO_END_ERRVAL +# define PSEUDO_END_ERRVAL(name) \ +  END (name) + +# define ret_ERRVAL ret + +# ifndef __PIC__ +#  define SYSCALL_ERROR_HANDLER	/* Nothing here; code in sysdep.S is used.  */ +# elif defined(RTLD_PRIVATE_ERRNO) +#  define SYSCALL_ERROR_HANDLER			\ +0:						\ +  leaq rtld_errno(%rip), %rcx;			\ +  xorl %edx, %edx;				\ +  subq %rax, %rdx;				\ +  movl %edx, (%rcx);				\ +  orq $-1, %rax;				\ +  jmp L(pseudo_end); +# elif USE___THREAD +#  ifndef NOT_IN_libc +#   define SYSCALL_ERROR_ERRNO __libc_errno +#  else +#   define SYSCALL_ERROR_ERRNO errno +#  endif +#  define SYSCALL_ERROR_HANDLER			\ +0:						\ +  movq SYSCALL_ERROR_ERRNO@GOTTPOFF(%rip), %rcx;\ +  xorl %edx, %edx;				\ +  subq %rax, %rdx;				\ +  movl %edx, %fs:(%rcx);			\ +  orq $-1, %rax;				\ +  jmp L(pseudo_end); +# elif defined _LIBC_REENTRANT +/* Store (- %rax) into errno through the GOT. +   Note that errno occupies only 4 bytes.  */ +#  define SYSCALL_ERROR_HANDLER			\ +0:						\ +  xorl %edx, %edx;				\ +  subq %rax, %rdx;				\ +  pushq %rdx;					\ +  cfi_adjust_cfa_offset(8);			\ +  call __errno_location@PLT;		\ +  popq %rdx;					\ +  cfi_adjust_cfa_offset(-8);			\ +  movl %edx, (%rax);				\ +  orq $-1, %rax;				\ +  jmp L(pseudo_end); + +/* A quick note: it is assumed that the call to `__errno_location' does +   not modify the stack!  */ +# else /* Not _LIBC_REENTRANT.  */ +#  define SYSCALL_ERROR_HANDLER			\ +0:movq errno@GOTPCREL(%RIP), %rcx;		\ +  xorl %edx, %edx;				\ +  subq %rax, %rdx;				\ +  movl %edx, (%rcx);				\ +  orq $-1, %rax;				\ +  jmp L(pseudo_end); +# endif	/* __PIC__ */ + +/* The Linux/x86-64 kernel expects the system call parameters in +   registers according to the following table: + +    syscall number	rax +    arg 1		rdi +    arg 2		rsi +    arg 3		rdx +    arg 4		r10 +    arg 5		r8 +    arg 6		r9 + +    The Linux kernel uses and destroys internally these registers: +    return address from +    syscall		rcx +    eflags from syscall	r11 + +    Normal function call, including calls to the system call stub +    functions in the libc, get the first six parameters passed in +    registers and the seventh parameter and later on the stack.  The +    register use is as follows: + +     system call number	in the DO_CALL macro +     arg 1		rdi +     arg 2		rsi +     arg 3		rdx +     arg 4		rcx +     arg 5		r8 +     arg 6		r9 + +    We have to take care that the stack is aligned to 16 bytes.  When +    called the stack is not aligned since the return address has just +    been pushed. + + +    Syscalls of more than 6 arguments are not supported.  */ + +# undef	DO_CALL +# define DO_CALL(syscall_name, args)		\ +    DOARGS_##args				\ +    movl $SYS_ify (syscall_name), %eax;		\ +    syscall; + +# define DOARGS_0 /* nothing */ +# define DOARGS_1 /* nothing */ +# define DOARGS_2 /* nothing */ +# define DOARGS_3 /* nothing */ +# define DOARGS_4 movq %rcx, %r10; +# define DOARGS_5 DOARGS_4 +# define DOARGS_6 DOARGS_5 + +#endif	/* __ASSEMBLER__ */ + + +/* Pointer mangling support.  */ +#if defined NOT_IN_libc && defined IS_IN_rtld +/* We cannot use the thread descriptor because in ld.so we use setjmp +   earlier than the descriptor is initialized.  */ +# ifdef __ASSEMBLER__ +#  define PTR_MANGLE(reg)	xorq __pointer_chk_guard_local(%rip), reg;    \ +				rolq $17, reg +#  define PTR_DEMANGLE(reg)	rorq $17, reg;				      \ +				xorq __pointer_chk_guard_local(%rip), reg +# else +#  define PTR_MANGLE(reg)	asm ("xorq __pointer_chk_guard_local(%%rip), %0\n" \ +				     "rolq $17, %0"			      \ +				     : "=r" (reg) : "0" (reg)) +#  define PTR_DEMANGLE(reg)	asm ("rorq $17, %0\n"			      \ +				     "xorq __pointer_chk_guard_local(%%rip), %0" \ +				     : "=r" (reg) : "0" (reg)) +# endif +#else +# ifdef __ASSEMBLER__ +#  define PTR_MANGLE(reg)	xorq %fs:POINTER_GUARD, reg;		      \ +				rolq $17, reg +#  define PTR_DEMANGLE(reg)	rorq $17, reg;				      \ +				xorq %fs:POINTER_GUARD, reg +# else +#  define PTR_MANGLE(var)	asm ("xorq %%fs:%c2, %0\n"		      \ +				     "rolq $17, %0"			      \ +				     : "=r" (var)			      \ +				     : "0" (var),			      \ +				       "i" (offsetof (tcbhead_t,	      \ +						      pointer_guard))) +#  define PTR_DEMANGLE(var)	asm ("rorq $17, %0\n"			      \ +				     "xorq %%fs:%c2, %0"		      \ +				     : "=r" (var)			      \ +				     : "0" (var),			      \ +				       "i" (offsetof (tcbhead_t,	      \ +						      pointer_guard))) +# endif +#endif + +#endif /* linux/x86_64/sysdep.h */ 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 diff --git a/libpthread/nptl/sysdeps/x86_64/Makefile b/libpthread/nptl/sysdeps/x86_64/Makefile new file mode 100644 index 000000000..2f0d88f30 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/Makefile @@ -0,0 +1,27 @@ +# Copyright (C) 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; if not, write to the Free +# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# 02111-1307 USA. + +ifeq ($(subdir),csu) +gen-as-const-headers += tcb-offsets.sym +endif + +ifeq ($(subdir),nptl) +CFLAGS-pthread_create.c += -mpreferred-stack-boundary=4 +CFLAGS-tst-align.c += -mpreferred-stack-boundary=4 +CFLAGS-tst-align2.c += -mpreferred-stack-boundary=4 +endif diff --git a/libpthread/nptl/sysdeps/x86_64/Makefile.arch b/libpthread/nptl/sysdeps/x86_64/Makefile.arch new file mode 100644 index 000000000..c1d683fac --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/Makefile.arch @@ -0,0 +1,53 @@ +# 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. +# + +libpthread_CSRC = pthread_spin_lock.c +libpthread_SSRC = pthread_spin_trylock.S + +CFLAGS-pthread_spin_lock.c += -D_GNU_SOURCE + +CFLAGS-x86_64 = $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +PTHREAD_ARCH_DIR := $(top_srcdir)libpthread/nptl/sysdeps/x86_64 +PTHREAD_ARCH_OUT := $(top_builddir)libpthread/nptl/sysdeps/x86_64 +PTHREAD_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_SSRC)) +PTHREAD_ARCH_OBJ += $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(PTHREAD_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(PTHREAD_ARCH_OBJ) +endif +libpthread-so-y += $(PTHREAD_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y += $(PTHREAD_ARCH_OBJ) + +objclean-y += nptl_arch_clean +headers_clean-y += nptl_arch_headers_clean + +# +# Create 'tcb-offsets.h' header file. +# +CFLAGS-tcb-offsets.c = -S + +$(PTHREAD_ARCH_OUT)/tcb-offsets.c: $(PTHREAD_ARCH_DIR)/tcb-offsets.sym +	$(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_ARCH_OUT)/tcb-offsets.s: $(PTHREAD_ARCH_OUT)/tcb-offsets.c +	$(compile.c) + +$(PTHREAD_ARCH_OUT)/tcb-offsets.h: $(PTHREAD_ARCH_OUT)/tcb-offsets.s +	@sed -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +nptl_arch_headers: $(PTHREAD_ARCH_OUT)/tcb-offsets.h + +nptl_arch_headers_clean: +	$(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/tcb-offsets., c s h) + +nptl_arch_clean: +	$(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/x86_64/dl-tls.h b/libpthread/nptl/sysdeps/x86_64/dl-tls.h new file mode 100644 index 000000000..3e4768dc1 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/dl-tls.h @@ -0,0 +1,29 @@ +/* Thread-local storage handling in the ELF dynamic linker.  x86-64 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 Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License 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.  */ + + +/* Type used for the representation of TLS information in the GOT.  */ +typedef struct +{ +  unsigned long int ti_module; +  unsigned long int ti_offset; +} tls_index; + + +extern void *__tls_get_addr (tls_index *ti); diff --git a/libpthread/nptl/sysdeps/x86_64/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/x86_64/jmpbuf-unwind.h new file mode 100644 index 000000000..345ed557c --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/jmpbuf-unwind.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2003, 2004 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 <setjmp.h> +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ +  _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ +  ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_RSP] - (_adj)) + +/* We use the normal lobngjmp for unwinding.  */ +#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/x86_64/pthread_spin_init.c b/libpthread/nptl/sysdeps/x86_64/pthread_spin_init.c new file mode 100644 index 000000000..55696204c --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/pthread_spin_init.c @@ -0,0 +1 @@ +#include "../i386/pthread_spin_init.c" diff --git a/libpthread/nptl/sysdeps/x86_64/pthread_spin_lock.c b/libpthread/nptl/sysdeps/x86_64/pthread_spin_lock.c new file mode 100644 index 000000000..7cf0e0ecc --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/pthread_spin_lock.c @@ -0,0 +1 @@ +#include "../i386/pthread_spin_lock.c" diff --git a/libpthread/nptl/sysdeps/x86_64/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/x86_64/pthread_spin_trylock.S new file mode 100644 index 000000000..9b5133583 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/pthread_spin_trylock.S @@ -0,0 +1,40 @@ +/* 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 <pthread-errnos.h> + + +#ifdef UP +# define LOCK +#else +# define LOCK lock +#endif + +	.globl	pthread_spin_trylock +	.type	pthread_spin_trylock,@function +	.align	16 +pthread_spin_trylock: +	movl	$1, %eax +	xorl	%ecx, %ecx +	LOCK +	cmpxchgl %ecx, (%rdi) +	movl	$EBUSY, %eax +	cmovel	%ecx, %eax +	retq +	.size	pthread_spin_trylock,.-pthread_spin_trylock diff --git a/libpthread/nptl/sysdeps/x86_64/pthread_spin_unlock.S b/libpthread/nptl/sysdeps/x86_64/pthread_spin_unlock.S new file mode 100644 index 000000000..d3e13bde9 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/pthread_spin_unlock.S @@ -0,0 +1,31 @@ +/* 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.  */ + +	.globl	pthread_spin_unlock +	.type	pthread_spin_unlock,@function +	.align	16 +pthread_spin_unlock: +	movl	$1, (%rdi) +	xorl	%eax, %eax +	retq +	.size	pthread_spin_unlock,.-pthread_spin_unlock + +	/* The implementation of pthread_spin_init is identical.  */ +	.globl	pthread_spin_init +pthread_spin_init = pthread_spin_unlock diff --git a/libpthread/nptl/sysdeps/x86_64/pthreaddef.h b/libpthread/nptl/sysdeps/x86_64/pthreaddef.h new file mode 100644 index 000000000..b33c18638 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/pthreaddef.h @@ -0,0 +1,43 @@ +/* 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.  */ + +/* Default stack size.  */ +#define ARCH_STACK_DEFAULT_SIZE	(2 * 1024 * 1024) + +/* Required stack pointer alignment at beginning.  SSE requires 16 +   bytes.  */ +#define STACK_ALIGN		16 + +/* Minimal stack size after allocating thread descriptor and guard size.  */ +#define MINIMAL_REST_STACK	2048 + +/* Alignment requirement for TCB.  */ +#define TCB_ALIGNMENT		16 + + +/* Location of current stack frame.  The frame pointer is not usable.  */ +#define CURRENT_STACK_FRAME \ +  ({ char *frame; __asm__ ("movq %%rsp, %0" : "=r" (frame)); frame; }) + + +/* XXX Until we have a better place keep the definitions here.  */ + +/* While there is no such syscall.  */ +#define __exit_thread_inline(val) \ +  __asm__ volatile ("syscall" :: "a" (__NR_exit), "D" (val)) diff --git a/libpthread/nptl/sysdeps/x86_64/sysdep.h b/libpthread/nptl/sysdeps/x86_64/sysdep.h new file mode 100644 index 000000000..ac74b7c23 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/sysdep.h @@ -0,0 +1,114 @@ +/* Assembler macros for x86-64. +   Copyright (C) 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; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdeps/generic/sysdep.h> + +#ifdef	__ASSEMBLER__ + +/* Syntactic details of assembler.  */ + +#ifdef HAVE_ELF + +/* ELF uses byte-counts for .align, most others use log2 of count of bytes.  */ +#define ALIGNARG(log2) 1<<log2 +/* For ELF we need the `.type' directive to make shared libs work right.  */ +#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,typearg; +#define ASM_SIZE_DIRECTIVE(name) .size name,.-name; + +/* In ELF C symbols are asm symbols.  */ +#undef	NO_UNDERSCORES +#define NO_UNDERSCORES + +#else + +#define ALIGNARG(log2) log2 +#define ASM_TYPE_DIRECTIVE(name,type)	/* Nothing is specified.  */ +#define ASM_SIZE_DIRECTIVE(name)	/* Nothing is specified.  */ + +#endif + + +/* Define an entry point visible from C.  */ +#define	ENTRY(name)							      \ +  ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name);				      \ +  ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function)			      \ +  .align ALIGNARG(4);							      \ +  C_LABEL(name)								      \ +  cfi_startproc;							      \ +  CALL_MCOUNT + +#undef	END +#define END(name)							      \ +  cfi_endproc;								      \ +  ASM_SIZE_DIRECTIVE(name) + +/* If compiled for profiling, call `mcount' at the start of each function.  */ +#ifdef	PROF +/* The mcount code relies on a normal frame pointer being on the stack +   to locate our caller, so push one just for its benefit.  */ +#define CALL_MCOUNT                                                          \ +  pushq %rbp;                                                                \ +  cfi_adjust_cfa_offset(8);                                                  \ +  movq %rsp, %rbp;                                                           \ +  cfi_def_cfa_register(%rbp);                                                \ +  call JUMPTARGET(mcount);                                                   \ +  popq %rbp;                                                                 \ +  cfi_def_cfa(rsp,8); +#else +#define CALL_MCOUNT		/* Do nothing.  */ +#endif + +#ifdef	NO_UNDERSCORES +/* Since C identifiers are not normally prefixed with an underscore +   on this system, the asm identifier `syscall_error' intrudes on the +   C name space.  Make sure we use an innocuous name.  */ +#define	syscall_error	__syscall_error +#define mcount		_mcount +#endif + +#define	PSEUDO(name, syscall_name, args)				      \ +lose:									      \ +  jmp JUMPTARGET(syscall_error)						      \ +  .globl syscall_error;							      \ +  ENTRY (name)								      \ +  DO_CALL (syscall_name, args);						      \ +  jb lose + +#undef	PSEUDO_END +#define	PSEUDO_END(name)						      \ +  END (name) + +#undef JUMPTARGET +#ifdef __PIC__ +#define JUMPTARGET(name)	name##@PLT +#else +#define JUMPTARGET(name)	name +#endif + +/* Local label name for asm code. */ +#ifndef L +# ifdef HAVE_ELF +/* ELF-like local names start with `.L'.  */ +#  define L(name)	.L##name +# else +#  define L(name)	name +# endif +#endif + +#endif	/* __ASSEMBLER__ */ diff --git a/libpthread/nptl/sysdeps/x86_64/tcb-offsets.sym b/libpthread/nptl/sysdeps/x86_64/tcb-offsets.sym new file mode 100644 index 000000000..8118d2df8 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/tcb-offsets.sym @@ -0,0 +1,12 @@ +#include <sysdep.h> +#include <tls.h> + +RESULT			offsetof (struct pthread, result) +TID			offsetof (struct pthread, tid) +PID			offsetof (struct pthread, pid) +CANCELHANDLING		offsetof (struct pthread, cancelhandling) +CLEANUP_JMP_BUF		offsetof (struct pthread, cleanup_jmp_buf) +CLEANUP			offsetof (struct pthread, cleanup) +CLEANUP_PREV		offsetof (struct _pthread_cleanup_buffer, __prev) +MUTEX_FUTEX		offsetof (pthread_mutex_t, __data.__lock) +MULTIPLE_THREADS_OFFSET	offsetof (tcbhead_t, multiple_threads) diff --git a/libpthread/nptl/sysdeps/x86_64/tls.h b/libpthread/nptl/sysdeps/x86_64/tls.h new file mode 100644 index 000000000..7b40e3d57 --- /dev/null +++ b/libpthread/nptl/sysdeps/x86_64/tls.h @@ -0,0 +1,437 @@ +/* Definition for thread-local data handling.  nptl/x86_64 version. +   Copyright (C) 2002-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 _TLS_H +#define _TLS_H	1 + +#ifndef __ASSEMBLER__ +# include <asm/prctl.h>	/* For ARCH_SET_FS.  */ +# include <stdbool.h> +# include <stddef.h> +# include <stdint.h> +# include <stdlib.h> +# include <sysdep.h> +# include <bits/wordsize.h> +# include <xmmintrin.h> + + +/* Type for the dtv.  */ +typedef union dtv +{ +  size_t counter; +  struct +  { +    void *val; +    bool is_static; +  } pointer; +} dtv_t; + + +typedef struct +{ +  void *tcb;		/* Pointer to the TCB.  Not necessarily the +			   thread descriptor used by libpthread.  */ +  dtv_t *dtv; +  void *self;		/* Pointer to the thread descriptor.  */ +  int multiple_threads; +  int gscope_flag; +  uintptr_t sysinfo; +  uintptr_t stack_guard; +  uintptr_t pointer_guard; +  unsigned long int vgetcpu_cache[2]; +# ifndef __ASSUME_PRIVATE_FUTEX +  int private_futex; +# else +  int __unused1; +# endif +# if __WORDSIZE == 64 +  int rtld_must_xmm_save; +# endif +  /* Reservation of some values for the TM ABI.  */ +  void *__private_tm[5]; +# if __WORDSIZE == 64 +  long int __unused2; +  /* Have space for the post-AVX register size.  */ +  __m128 rtld_savespace_sse[8][4]; + +  void *__padding[8]; +# endif +} tcbhead_t; + +#else /* __ASSEMBLER__ */ +# include <tcb-offsets.h> +#endif + + +/* We require TLS support in the tools.  */ +#define HAVE_TLS_SUPPORT                1 +#define HAVE___THREAD 1 +#define HAVE_TLS_MODEL_ATTRIBUTE 1 + +/* Signal that TLS support is available.  */ +#define USE_TLS	1 + +/* Alignment requirement for the stack.  */ +#define STACK_ALIGN	16 + + +#ifndef __ASSEMBLER__ +/* Get system call information.  */ +# include <sysdep.h> + + +/* Get the thread descriptor definition.  */ +# include <descr.h> + +#ifndef LOCK_PREFIX +# ifdef UP +#  define LOCK_PREFIX	/* nothing */ +# else +#  define LOCK_PREFIX	"lock;" +# endif +#endif + +/* This is the size of the initial TCB.  Can't be just sizeof (tcbhead_t), +   because NPTL getpid, __libc_alloca_cutoff etc. need (almost) the whole +   struct pthread even when not linked with -lpthread.  */ +# define TLS_INIT_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the initial TCB.  */ +# define TLS_INIT_TCB_ALIGN __alignof__ (struct pthread) + +/* This is the size of the TCB.  */ +# define TLS_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the TCB.  */ +//# define TLS_TCB_ALIGN __alignof__ (struct pthread) +// Normally the above would be correct  But we have to store post-AVX +// vector registers in the TCB and we want the storage to be aligned. +// unfortunately there isn't yet a type for these values and hence no +// 32-byte alignment requirement.  Make this explicit, for now. +# define TLS_TCB_ALIGN 32 + +/* The TCB can have any size and the memory following the address the +   thread pointer points to is unspecified.  Allocate the TCB there.  */ +# define TLS_TCB_AT_TP	1 + + +/* Install the dtv pointer.  The pointer passed is to the element with +   index -1 which contain the length.  */ +# define INSTALL_DTV(descr, dtvp) \ +  ((tcbhead_t *) (descr))->dtv = (dtvp) + 1 + +/* Install new dtv for current thread.  */ +# define INSTALL_NEW_DTV(dtvp) \ +  ({ struct pthread *__pd;						      \ +     THREAD_SETMEM (__pd, header.dtv, (dtvp)); }) + +/* Return dtv of given thread descriptor.  */ +# define GET_DTV(descr) \ +  (((tcbhead_t *) (descr))->dtv) + + +/* Macros to load from and store into segment registers.  */ +# define TLS_GET_FS() \ +  ({ int __seg; __asm__ ("movl %%fs, %0" : "=q" (__seg)); __seg; }) +# define TLS_SET_FS(val) \ +  __asm__ ("movl %0, %%fs" :: "q" (val)) + + +/* Code to initially initialize the thread pointer.  This might need +   special attention since 'errno' is not yet available and if the +   operation can cause a failure 'errno' must not be touched. + +   We have to make the syscall for both uses of the macro since the +   address might be (and probably is) different.  */ +# define TLS_INIT_TP(thrdescr, secondcall) \ +  ({ void *_thrdescr = (thrdescr);					      \ +     tcbhead_t *_head = _thrdescr;					      \ +     int _result;							      \ +									      \ +     _head->tcb = _thrdescr;						      \ +     /* For now the thread descriptor is at the same address.  */	      \ +     _head->self = _thrdescr;						      \ +									      \ +     /* It is a simple syscall to set the %fs value for the thread.  */	      \ +     __asm__ volatile ("syscall"						      \ +		   : "=a" (_result)					      \ +		   : "0" ((unsigned long int) __NR_arch_prctl),		      \ +		     "D" ((unsigned long int) ARCH_SET_FS),		      \ +		     "S" (_thrdescr)					      \ +		   : "memory", "cc", "r11", "cx");			      \ +									      \ +    _result ? "cannot set %fs base address for thread-local storage" : 0;     \ +  }) + + +/* Return the address of the dtv for the current thread.  */ +# define THREAD_DTV() \ +  ({ struct pthread *__pd;						      \ +     THREAD_GETMEM (__pd, header.dtv); }) + + +/* Return the thread descriptor for the current thread. + +   The contained asm must *not* be marked volatile since otherwise +   assignments like +	pthread_descr self = thread_self(); +   do not get optimized away.  */ +# define THREAD_SELF \ +  ({ struct pthread *__self;						      \ +     __asm__ ("movq %%fs:%c1,%q0" : "=r" (__self)				      \ +	  : "i" (offsetof (struct pthread, header.self)));	 	      \ +     __self;}) + +/* Magic for libthread_db to know how to do THREAD_SELF.  */ +# define DB_THREAD_SELF_INCLUDE  <sys/reg.h> /* For the FS constant.  */ +# define DB_THREAD_SELF CONST_THREAD_AREA (64, FS) + +/* Read member of the thread descriptor directly.  */ +# define THREAD_GETMEM(descr, member) \ +  ({ __typeof (descr->member) __value;					      \ +     if (sizeof (__value) == 1)						      \ +       __asm__ volatile ("movb %%fs:%P2,%b0"				      \ +		     : "=q" (__value)					      \ +		     : "0" (0), "i" (offsetof (struct pthread, member)));     \ +     else if (sizeof (__value) == 4)					      \ +       __asm__ volatile ("movl %%fs:%P1,%0"					      \ +		     : "=r" (__value)					      \ +		     : "i" (offsetof (struct pthread, member)));	      \ +     else								      \ +       {								      \ +	 if (sizeof (__value) != 8)					      \ +	   /* There should not be any value with a size other than 1,	      \ +	      4 or 8.  */						      \ +	   abort ();							      \ +									      \ +	 __asm__ volatile ("movq %%fs:%P1,%q0"				      \ +		       : "=r" (__value)					      \ +		       : "i" (offsetof (struct pthread, member)));	      \ +       }								      \ +     __value; }) + + +/* Same as THREAD_GETMEM, but the member offset can be non-constant.  */ +# define THREAD_GETMEM_NC(descr, member, idx) \ +  ({ __typeof (descr->member[0]) __value;				      \ +     if (sizeof (__value) == 1)						      \ +       __asm__ volatile ("movb %%fs:%P2(%q3),%b0"				      \ +		     : "=q" (__value)					      \ +		     : "0" (0), "i" (offsetof (struct pthread, member[0])),   \ +		       "r" (idx));					      \ +     else if (sizeof (__value) == 4)					      \ +       __asm__ volatile ("movl %%fs:%P1(,%q2,4),%0"				      \ +		     : "=r" (__value)					      \ +		     : "i" (offsetof (struct pthread, member[0])), "r" (idx));\ +     else								      \ +       {								      \ +	 if (sizeof (__value) != 8)					      \ +	   /* There should not be any value with a size other than 1,	      \ +	      4 or 8.  */						      \ +	   abort ();							      \ +									      \ +	 __asm__ volatile ("movq %%fs:%P1(,%q2,8),%q0"			      \ +		       : "=r" (__value)					      \ +		       : "i" (offsetof (struct pthread, member[0])),	      \ +			 "r" (idx));					      \ +       }								      \ +     __value; }) + + +/* Loading addresses of objects on x86-64 needs to be treated special +   when generating PIC code.  */ +#ifdef __pic__ +# define IMM_MODE "nr" +#else +# define IMM_MODE "ir" +#endif + + +/* Same as THREAD_SETMEM, but the member offset can be non-constant.  */ +# define THREAD_SETMEM(descr, member, value) \ +  ({ if (sizeof (descr->member) == 1)					      \ +       __asm__ volatile ("movb %b0,%%fs:%P1" :				      \ +		     : "iq" (value),					      \ +		       "i" (offsetof (struct pthread, member)));	      \ +     else if (sizeof (descr->member) == 4)				      \ +       __asm__ volatile ("movl %0,%%fs:%P1" :				      \ +		     : IMM_MODE (value),				      \ +		       "i" (offsetof (struct pthread, member)));	      \ +     else								      \ +       {								      \ +	 if (sizeof (descr->member) != 8)				      \ +	   /* There should not be any value with a size other than 1,	      \ +	      4 or 8.  */						      \ +	   abort ();							      \ +									      \ +	 __asm__ volatile ("movq %q0,%%fs:%P1" :				      \ +		       : IMM_MODE ((unsigned long int) value),		      \ +			 "i" (offsetof (struct pthread, member)));	      \ +       }}) + + +/* Set member of the thread descriptor directly.  */ +# define THREAD_SETMEM_NC(descr, member, idx, value) \ +  ({ if (sizeof (descr->member[0]) == 1)				      \ +       __asm__ volatile ("movb %b0,%%fs:%P1(%q2)" :				      \ +		     : "iq" (value),					      \ +		       "i" (offsetof (struct pthread, member[0])),	      \ +		       "r" (idx));					      \ +     else if (sizeof (descr->member[0]) == 4)				      \ +       __asm__ volatile ("movl %0,%%fs:%P1(,%q2,4)" :			      \ +		     : IMM_MODE (value),				      \ +		       "i" (offsetof (struct pthread, member[0])),	      \ +		       "r" (idx));					      \ +     else								      \ +       {								      \ +	 if (sizeof (descr->member[0]) != 8)				      \ +	   /* There should not be any value with a size other than 1,	      \ +	      4 or 8.  */						      \ +	   abort ();							      \ +									      \ +	 __asm__ volatile ("movq %q0,%%fs:%P1(,%q2,8)" :			      \ +		       : IMM_MODE ((unsigned long int) value),		      \ +			 "i" (offsetof (struct pthread, member[0])),	      \ +			 "r" (idx));					      \ +       }}) + + +/* Atomic compare and exchange on TLS, returning old value.  */ +# define THREAD_ATOMIC_CMPXCHG_VAL(descr, member, newval, oldval) \ +  ({ __typeof (descr->member) __ret;					      \ +     __typeof (oldval) __old = (oldval);				      \ +     if (sizeof (descr->member) == 4)					      \ +       __asm__ volatile (LOCK_PREFIX "cmpxchgl %2, %%fs:%P3"		      \ +		     : "=a" (__ret)					      \ +		     : "0" (__old), "r" (newval),			      \ +		       "i" (offsetof (struct pthread, member)));	      \ +     else								      \ +       /* Not necessary for other sizes in the moment.  */		      \ +       abort ();							      \ +     __ret; }) + + +/* Atomic logical and.  */ +# define THREAD_ATOMIC_AND(descr, member, val) \ +  (void) ({ if (sizeof ((descr)->member) == 4)				      \ +	      __asm__ volatile (LOCK_PREFIX "andl %1, %%fs:%P0"		      \ +			    :: "i" (offsetof (struct pthread, member)),	      \ +			       "ir" (val));				      \ +	    else							      \ +	      /* Not necessary for other sizes in the moment.  */	      \ +	      abort (); }) + + +/* Atomic set bit.  */ +# define THREAD_ATOMIC_BIT_SET(descr, member, bit) \ +  (void) ({ if (sizeof ((descr)->member) == 4)				      \ +	      __asm__ volatile (LOCK_PREFIX "orl %1, %%fs:%P0"		      \ +			    :: "i" (offsetof (struct pthread, member)),	      \ +			       "ir" (1 << (bit)));			      \ +	    else							      \ +	      /* Not necessary for other sizes in the moment.  */	      \ +	      abort (); }) + + +# define CALL_THREAD_FCT(descr) \ +  ({ void *__res;							      \ +     __asm__ volatile ("movq %%fs:%P2, %%rdi\n\t"				      \ +		   "callq *%%fs:%P1"					      \ +		   : "=a" (__res)					      \ +		   : "i" (offsetof (struct pthread, start_routine)),	      \ +		     "i" (offsetof (struct pthread, arg))		      \ +		   : "di", "si", "cx", "dx", "r8", "r9", "r10", "r11",	      \ +		     "memory", "cc");					      \ +     __res; }) + + +/* Set the stack guard field in TCB head.  */ +# define THREAD_SET_STACK_GUARD(value) \ +    THREAD_SETMEM (THREAD_SELF, header.stack_guard, value) +# define THREAD_COPY_STACK_GUARD(descr) \ +    ((descr)->header.stack_guard					      \ +     = THREAD_GETMEM (THREAD_SELF, header.stack_guard)) + + +/* Set the pointer guard field in the TCB head.  */ +# define THREAD_SET_POINTER_GUARD(value) \ +  THREAD_SETMEM (THREAD_SELF, header.pointer_guard, value) +# define THREAD_COPY_POINTER_GUARD(descr) \ +  ((descr)->header.pointer_guard					      \ +   = THREAD_GETMEM (THREAD_SELF, header.pointer_guard)) + + +/* Get and set the global scope generation counter in the TCB head.  */ +# define THREAD_GSCOPE_FLAG_UNUSED 0 +# define THREAD_GSCOPE_FLAG_USED   1 +# define THREAD_GSCOPE_FLAG_WAIT   2 +# define THREAD_GSCOPE_RESET_FLAG() \ +  do									      \ +    { int __res;							      \ +      __asm__ volatile ("xchgl %0, %%fs:%P1"				      \ +		    : "=r" (__res)					      \ +		    : "i" (offsetof (struct pthread, header.gscope_flag)),    \ +		      "0" (THREAD_GSCOPE_FLAG_UNUSED));			      \ +      if (__res == THREAD_GSCOPE_FLAG_WAIT)				      \ +	lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE);    \ +    }									      \ +  while (0) +# define THREAD_GSCOPE_SET_FLAG() \ +  THREAD_SETMEM (THREAD_SELF, header.gscope_flag, THREAD_GSCOPE_FLAG_USED) +# define THREAD_GSCOPE_WAIT() \ +  GL(dl_wait_lookup_done) () + + +# ifdef SHARED +/* Defined in dl-trampoline.S.  */ +extern void _dl_x86_64_save_sse (void); +extern void _dl_x86_64_restore_sse (void); + +# define RTLD_CHECK_FOREIGN_CALL \ +  (THREAD_GETMEM (THREAD_SELF, header.rtld_must_xmm_save) != 0) + +/* NB: Don't use the xchg operation because that would imply a lock +   prefix which is expensive and unnecessary.  The cache line is also +   not contested at all.  */ +#  define RTLD_ENABLE_FOREIGN_CALL \ +  int old_rtld_must_xmm_save = THREAD_GETMEM (THREAD_SELF,		      \ +					      header.rtld_must_xmm_save);     \ +  THREAD_SETMEM (THREAD_SELF, header.rtld_must_xmm_save, 1) + +#  define RTLD_PREPARE_FOREIGN_CALL \ +  do if (THREAD_GETMEM (THREAD_SELF, header.rtld_must_xmm_save))	      \ +    {									      \ +      _dl_x86_64_save_sse ();						      \ +      THREAD_SETMEM (THREAD_SELF, header.rtld_must_xmm_save, 0);	      \ +    }									      \ +  while (0) + +#  define RTLD_FINALIZE_FOREIGN_CALL \ +  do {									      \ +    if (THREAD_GETMEM (THREAD_SELF, header.rtld_must_xmm_save) == 0)	      \ +      _dl_x86_64_restore_sse ();					      \ +    THREAD_SETMEM (THREAD_SELF, header.rtld_must_xmm_save,		      \ +		   old_rtld_must_xmm_save);				      \ +  } while (0) +# endif + + +#endif /* __ASSEMBLER__ */ + +#endif	/* tls.h */  | 
