diff options
Diffstat (limited to 'libpthread/nptl/sysdeps/pthread')
45 files changed, 5677 insertions, 0 deletions
| 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..2a825329a --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/Makefile.in @@ -0,0 +1,146 @@ +# 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_cond_wait.c pthread_barrier_wait.c pthread_cond_broadcast.c	\ +		pthread_cond_signal.c pthread_cond_timedwait.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) +libpthread_CSRC += pthread_once.c +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..c6b563f24 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_barrier_wait.c @@ -0,0 +1,77 @@ +/* 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 (barrier) +     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..d83524182 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_cond_broadcast.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 <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 (cond) +     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..863b0a029 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_cond_signal.c @@ -0,0 +1,52 @@ +/* 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 (cond) +     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..db9dc4dcd --- /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 (cond, mutex, abstime) +     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..b0fe694ba --- /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 (cond, mutex) +     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..9b2cef864 --- /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 (once_control, init_routine) +     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..e225d7030 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_rdlock.c @@ -0,0 +1,95 @@ +/* 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 (rwlock) +     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..80ea83a3d --- /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 (rwlock, abstime) +     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..97c0598f9 --- /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 (rwlock, abstime) +     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..822aeed79 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_rwlock_wrlock.c @@ -0,0 +1,87 @@ +/* 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 (rwlock) +     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..0d12fe6bf --- /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 (how, newmask, oldmask) +     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..4d0109cf0 --- /dev/null +++ b/libpthread/nptl/sysdeps/pthread/pthread_spin_destroy.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 "pthreadP.h" + + +int +pthread_spin_destroy (lock) +     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..2809ac744 --- /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 (clock_id, evp, timerid) +     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..48ba1f272 --- /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 (timerid) +     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); +} | 
