diff options
Diffstat (limited to 'libpthread/nptl/sysdeps/unix/sysv/linux/mips')
12 files changed, 972 insertions, 0 deletions
| diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile new file mode 100644 index 000000000..43a6fad84 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../../../../ +top_builddir=../../../../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.arch +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile.arch new file mode 100644 index 000000000..8e7917bb0 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile.arch @@ -0,0 +1,50 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_SSRC = pt-vfork.S +libpthread_CSRC = pthread_once.c pt-__syscall_rt_sigaction.c + +libc_a_CSRC = fork.c + +CFLAGS-OMIT-fork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y) +CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__ +endif +CFLAGS-pthread_once.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-pt-__syscall_rt_sigaction.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +CFLAGS += $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/mips +LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/mips + +LINUX_ARCH_OBJ:=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libpthread_SSRC)) +LINUX_ARCH_OBJ+=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(LINUX_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(LINUX_ARCH_OBJ) +endif +libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y+=$(LINUX_ARCH_OBJS) + +LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC)) + +libc-static-y+=$(LIBC_LINUX_ARCH_OBJ) +libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS) + +libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ) + +objclean-y+=pthread_linux_arch_objclean + +pthread_linux_arch_objclean: +	$(RM) $(LINUX_ARCH_OUT)/*.{o,os,oS} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h new file mode 100644 index 000000000..166a6c6ae --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h @@ -0,0 +1,229 @@ +/* Machine-specific pthread type layouts.  MIPS version. +   Copyright (C) 2005, 2006 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H	1 + +#include <endian.h> + +#if _MIPS_SIM == _ABI64 +# define __SIZEOF_PTHREAD_ATTR_T 56 +# define __SIZEOF_PTHREAD_MUTEX_T 40 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 56 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 32 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#else +# define __SIZEOF_PTHREAD_ATTR_T 36 +# define __SIZEOF_PTHREAD_MUTEX_T 24 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 32 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 20 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#endif + + +/* Thread identifiers.  The structure of the attribute type is +   deliberately not exposed.  */ +typedef unsigned long int pthread_t; + + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_ATTR_T]; +  long int __align; +} pthread_attr_t; + + +#if _MIPS_SIM == _ABI64 +typedef struct __pthread_internal_list +{ +  struct __pthread_internal_list *__prev; +  struct __pthread_internal_list *__next; +} __pthread_list_t; +#else +typedef struct __pthread_internal_slist +{ +  struct __pthread_internal_slist *__next; +} __pthread_slist_t; +#endif + + +/* Data structures for mutex handling.  The structure of the attribute +   type is deliberately not exposed.  */ +typedef union +{ +  struct __pthread_mutex_s +  { +    int __lock; +    unsigned int __count; +    int __owner; +#if _MIPS_SIM == _ABI64 +    unsigned int __nusers; +#endif +    /* KIND must stay at this position in the structure to maintain +       binary compatibility.  */ +    int __kind; +#if _MIPS_SIM == _ABI64 +    int __spins; +    __pthread_list_t __list; +# define __PTHREAD_MUTEX_HAVE_PREV	1 +#else +    unsigned int __nusers; +    __extension__ union +    { +      int __spins; +      __pthread_slist_t __list; +    }; +#endif +  } __data; +  char __size[__SIZEOF_PTHREAD_MUTEX_T]; +  long int __align; +} pthread_mutex_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; +  int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling.  The structure of +   the attribute type is deliberately not exposed.  */ +typedef union +{ +  struct +  { +    int __lock; +    unsigned int __futex; +    __extension__ unsigned long long int __total_seq; +    __extension__ unsigned long long int __wakeup_seq; +    __extension__ unsigned long long int __woken_seq; +    void *__mutex; +    unsigned int __nwaiters; +    unsigned int __broadcast_seq; +  } __data; +  char __size[__SIZEOF_PTHREAD_COND_T]; +  __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_CONDATTR_T]; +  int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling.  The +   structure of the attribute type is deliberately not exposed.  */ +typedef union +{ +# if _MIPS_SIM == _ABI64 +  struct +  { +    int __lock; +    unsigned int __nr_readers; +    unsigned int __readers_wakeup; +    unsigned int __writer_wakeup; +    unsigned int __nr_readers_queued; +    unsigned int __nr_writers_queued; +    int __writer; +    int __shared; +    unsigned long int __pad1; +    unsigned long int __pad2; +    /* FLAGS must stay at this position in the structure to maintain +       binary compatibility.  */ +    unsigned int __flags; +  } __data; +# else +  struct +  { +    int __lock; +    unsigned int __nr_readers; +    unsigned int __readers_wakeup; +    unsigned int __writer_wakeup; +    unsigned int __nr_readers_queued; +    unsigned int __nr_writers_queued; +#if __BYTE_ORDER == __BIG_ENDIAN +    unsigned char __pad1; +    unsigned char __pad2; +    unsigned char __shared; +    /* FLAGS must stay at this position in the structure to maintain +       binary compatibility.  */ +    unsigned char __flags; +#else +    /* FLAGS must stay at this position in the structure to maintain +       binary compatibility.  */ +    unsigned char __flags; +    unsigned char __shared; +    unsigned char __pad1; +    unsigned char __pad2; +#endif +    int __writer; +  } __data; +# endif +  char __size[__SIZEOF_PTHREAD_RWLOCK_T]; +  long int __align; +} pthread_rwlock_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; +  long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type.  */ +typedef volatile int pthread_spinlock_t; + + +/* POSIX barriers data type.  The structure of the type is +   deliberately not exposed.  */ +typedef union +{ +  char __size[__SIZEOF_PTHREAD_BARRIER_T]; +  long int __align; +} pthread_barrier_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; +  int __align; +} pthread_barrierattr_t; +#endif + + +#endif	/* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h new file mode 100644 index 000000000..af43a6048 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h @@ -0,0 +1,37 @@ +/* Copyright (C) 2002, 2005, 2007 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + +#if _MIPS_SIM == _ABI64 +# define __SIZEOF_SEM_T	32 +#else +# define __SIZEOF_SEM_T	16 +#endif + +/* Value returned if `sem_open' failed.  */ +#define SEM_FAILED      ((sem_t *) 0) + + +typedef union +{ +  char __size[__SIZEOF_SEM_T]; +  long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/createthread.c new file mode 100644 index 000000000..d8a7c5539 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/createthread.c @@ -0,0 +1,24 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +/* Value passed to 'clone' for initialization of the thread register.  */ +#define TLS_VALUE ((void *) (pd) \ +		   + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE) + +/* Get the real implementation.	 */ +#include <sysdeps/pthread/createthread.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/fork.c new file mode 100644 index 000000000..06b7e1c69 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/fork.c @@ -0,0 +1 @@ +#include "../i386/fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h new file mode 100644 index 000000000..01bcf4120 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h @@ -0,0 +1,295 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, +   2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H	1 + +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> +#include <atomic.h> +#include <sysdep.h> +#include <bits/kernel-features.h> + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 +#define FUTEX_REQUEUE		3 +#define FUTEX_CMP_REQUEUE	4 +#define FUTEX_WAKE_OP		5 +#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE	((4 << 24) | 1) +#define FUTEX_LOCK_PI		6 +#define FUTEX_UNLOCK_PI		7 +#define FUTEX_TRYLOCK_PI	8 +#define FUTEX_WAIT_BITSET	9 +#define FUTEX_WAKE_BITSET	10 +#define FUTEX_PRIVATE_FLAG	128 +#define FUTEX_CLOCK_REALTIME	256 + +#define FUTEX_BITSET_MATCH_ANY	0xffffffff + +/* Values for 'private' parameter of locking macros.  Yes, the +   definition seems to be backwards.  But it is not.  The bit will be +   reversed before passing to the system call.  */ +#define LLL_PRIVATE	0 +#define LLL_SHARED	FUTEX_PRIVATE_FLAG + + +#if !defined NOT_IN_libc || defined IS_IN_rtld +/* In libc.so or ld.so all futexes are private.  */ +# ifdef __ASSUME_PRIVATE_FUTEX +#  define __lll_private_flag(fl, private) \ +  ((fl) | FUTEX_PRIVATE_FLAG) +# else +#  define __lll_private_flag(fl, private) \ +  ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex)) +# endif +#else +# ifdef __ASSUME_PRIVATE_FUTEX +#  define __lll_private_flag(fl, private) \ +  (((fl) | FUTEX_PRIVATE_FLAG) ^ (private)) +# else +#  define __lll_private_flag(fl, private) \ +  (__builtin_constant_p (private)					      \ +   ? ((private) == 0							      \ +      ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))	      \ +      : (fl))								      \ +   : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG)				      \ +	      & THREAD_GETMEM (THREAD_SELF, header.private_futex)))) +# endif	       +#endif + + +#define lll_futex_wait(futexp, val, private) \ +  lll_futex_timed_wait(futexp, val, NULL, private) + +#define lll_futex_timed_wait(futexp, val, timespec, private) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4, (long) (futexp),		      \ +			      __lll_private_flag (FUTEX_WAIT, private),	      \ +			      (val), (timespec));			      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;		      \ +  }) + +#define lll_futex_wake(futexp, nr, private) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4, (long) (futexp),		      \ +			      __lll_private_flag (FUTEX_WAKE, private),	      \ +			      (nr), 0);	      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;		      \ +  }) + +#define lll_robust_dead(futexv, private) \ +  do									      \ +    {									      \ +      int *__futexp = &(futexv);					      \ +      atomic_or (__futexp, FUTEX_OWNER_DIED);				      \ +      lll_futex_wake (__futexp, 1, private);				      \ +    }									      \ +  while (0) + +/* Returns non-zero if error happened, zero if success.  */ +#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val, private) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 6, (long) (futexp),		      \ +			      __lll_private_flag (FUTEX_CMP_REQUEUE, private),\ +			      (nr_wake), (nr_move), (mutex), (val));	      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err);				      \ +  }) + +/* Returns non-zero if error happened, zero if success.  */ +#define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +									      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),		      \ +			      __lll_private_flag (FUTEX_WAKE_OP, private),    \ +			      (nr_wake), (nr_wake2), (futexp2),		      \ +			      FUTEX_OP_CLEAR_WAKE_IF_GT_ONE);		      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err);				      \ +  }) + +static inline int __attribute__((always_inline)) +__lll_trylock(int *futex) +{ +  return atomic_compare_and_exchange_val_acq (futex, 1, 0) != 0; +} +#define lll_trylock(lock)	__lll_trylock (&(lock)) + + +static inline int __attribute__((always_inline)) +__lll_cond_trylock(int *futex) +{ +  return atomic_compare_and_exchange_val_acq (futex, 2, 0) != 0; +} +#define lll_cond_trylock(lock)	__lll_cond_trylock (&(lock)) + + +static inline int __attribute__((always_inline)) +__lll_robust_trylock(int *futex, int id) +{ +  return atomic_compare_and_exchange_val_acq (futex, id, 0) != 0; +} +#define lll_robust_trylock(lock, id) \ +  __lll_robust_trylock (&(lock), id) + +extern void __lll_lock_wait_private (int *futex) attribute_hidden; +extern void __lll_lock_wait (int *futex, int private) attribute_hidden; +extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden; + +#define __lll_lock(futex, private)					      \ +  ((void) ({								      \ +    int *__futex = (futex);						      \ +    if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex,      \ +								1, 0), 0))    \ +      {									      \ +	if (__builtin_constant_p (private) && (private) == LLL_PRIVATE)	      \ +	  __lll_lock_wait_private (__futex);				      \ +	else								      \ +	  __lll_lock_wait (__futex, private);				      \ +      }									      \ +  })) +#define lll_lock(futex, private) __lll_lock (&(futex), private) + + +#define __lll_robust_lock(futex, id, private)				      \ +  ({									      \ +    int *__futex = (futex);						      \ +    int __val = 0;							      \ +									      \ +    if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \ +								0), 0))	      \ +      __val = __lll_robust_lock_wait (__futex, private);		      \ +    __val;								      \ +  }) +#define lll_robust_lock(futex, id, private) \ +  __lll_robust_lock (&(futex), id, private) + + +static inline void __attribute__ ((always_inline)) +__lll_cond_lock (int *futex, int private) +{ +  if (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0) +    __lll_lock_wait (futex, private); +} +#define lll_cond_lock(futex, private) __lll_cond_lock (&(futex), private) + + +#define lll_robust_cond_lock(futex, id, private) \ +  __lll_robust_lock (&(futex), (id) | FUTEX_WAITERS, private) + + +extern int __lll_timedlock_wait (int *futex, const struct timespec *, +				 int private) attribute_hidden; +extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *, +					int private) attribute_hidden; + +static inline int __attribute__ ((always_inline)) +__lll_timedlock (int *futex, const struct timespec *abstime, int private) +{ +  int result = 0; +  if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0) +    result = __lll_timedlock_wait (futex, abstime, private); +  return result; +} +#define lll_timedlock(futex, abstime, private) \ +  __lll_timedlock (&(futex), abstime, private) + + +static inline int __attribute__ ((always_inline)) +__lll_robust_timedlock (int *futex, const struct timespec *abstime, +			int id, int private) +{ +  int result = 0; +  if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0) +    result = __lll_robust_timedlock_wait (futex, abstime, private); +  return result; +} +#define lll_robust_timedlock(futex, abstime, id, private) \ +  __lll_robust_timedlock (&(futex), abstime, id, private) + + +#define __lll_unlock(futex, private)					      \ +  ((void) ({								      \ +    int *__futex = (futex);						      \ +    int __val = atomic_exchange_rel (__futex, 0);			      \ +									      \ +    if (__builtin_expect (__val > 1, 0))				      \ +      lll_futex_wake (__futex, 1, private);				      \ +  })) +#define lll_unlock(futex, private) __lll_unlock(&(futex), private) + + +#define __lll_robust_unlock(futex, private)				      \ +  ((void) ({								      \ +    int *__futex = (futex);						      \ +    int __val = atomic_exchange_rel (__futex, 0);			      \ +									      \ +    if (__builtin_expect (__val & FUTEX_WAITERS, 0))			      \ +      lll_futex_wake (__futex, 1, private);				      \ +  })) +#define lll_robust_unlock(futex, private) \ +  __lll_robust_unlock(&(futex), private) + + +#define lll_islocked(futex) \ +  (futex != 0) + + +/* Our internal lock implementation is identical to the binary-compatible +   mutex implementation. */ + +/* Initializers for lock.  */ +#define LLL_LOCK_INITIALIZER		(0) +#define LLL_LOCK_INITIALIZER_LOCKED	(1) + +/* The states of a lock are: +    0  -  untaken +    1  -  taken by one user +   >1  -  taken by more users */ + +/* The kernel notifies a process which uses CLONE_CLEARTID via futex +   wakeup when the clone terminates.  The memory location contains the +   thread ID while the clone is running and is reset to zero +   afterwards.	*/ +#define lll_wait_tid(tid) \ +  do {							\ +    __typeof (tid) __tid;				\ +    while ((__tid = (tid)) != 0)			\ +      lll_futex_wait (&(tid), __tid, LLL_SHARED);	\ +  } while (0) + +extern int __lll_timedwait_tid (int *, const struct timespec *) +     attribute_hidden; + +#define lll_timedwait_tid(tid, abstime) \ +  ({							\ +    int __res = 0;					\ +    if ((tid) != 0)					\ +      __res = __lll_timedwait_tid (&(tid), (abstime));	\ +    __res;						\ +  }) + +#endif	/* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-__syscall_rt_sigaction.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-__syscall_rt_sigaction.c new file mode 100644 index 000000000..50137c84a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-__syscall_rt_sigaction.c @@ -0,0 +1 @@ +#include <../../../../../../../libc/sysdeps/linux/common/__syscall_rt_sigaction.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-clone.S new file mode 100644 index 000000000..add405523 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-clone.S @@ -0,0 +1,2 @@ +#define RESET_PID +#include <../../../../../../../libc/sysdeps/linux/mips/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S new file mode 100644 index 000000000..c02ffca93 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S @@ -0,0 +1,38 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <features.h> +#include <tls.h> + +/* Save the PID value.  */ +#define SAVE_PID \ +	READ_THREAD_POINTER(v1);	/* Get the thread pointer.  */	\ +	lw	a2, PID_OFFSET(v1);	/* Load the saved PID.  */	\ +	subu	a2, $0, a2;		/* Negate it.  */		\ +	sw	a2, PID_OFFSET(v1);	/* Store the temporary PID.  */ + +/* Restore the old PID value in the parent.  */ +#define RESTORE_PID \ +	beqz	v0, 1f;			/* If we are the parent... */	\ +	READ_THREAD_POINTER(v1);	/* Get the thread pointer.  */	\ +	lw	a2, PID_OFFSET(v1);	/* Load the saved PID.  */	\ +	subu	a2, $0, a2;		/* Re-negate it.  */		\ +	sw	a2, PID_OFFSET(v1);	/* Restore the PID.  */		\ +1: + +#include <../../../../../../../libc/sysdeps/linux/mips/vfork.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c new file mode 100644 index 000000000..ddfd32bdb --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c @@ -0,0 +1,94 @@ +/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "pthreadP.h" +#include <lowlevellock.h> + + +unsigned long int __fork_generation attribute_hidden; + + +static void +clear_once_control (void *arg) +{ +  pthread_once_t *once_control = (pthread_once_t *) arg; + +  *once_control = 0; +  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE); +} + + +int +__pthread_once (once_control, init_routine) +     pthread_once_t *once_control; +     void (*init_routine) (void); +{ +  while (1) +    { +      int oldval, val, newval; + +      val = *once_control; +      do +	{ +	  /* Check if the initialized has already been done.  */ +	  if ((val & 2) != 0) +	    return 0; + +	  oldval = val; +	  newval = (oldval & 3) | __fork_generation | 1; +	  val = atomic_compare_and_exchange_val_acq (once_control, newval, +						     oldval); +	} +      while (__builtin_expect (val != oldval, 0)); + +      /* Check if another thread already runs the initializer.	*/ +      if ((oldval & 1) != 0) +	{ +	  /* Check whether the initializer execution was interrupted +	     by a fork.	 */ +	  if (((oldval ^ newval) & -4) == 0) +	    { +	      /* Same generation, some other thread was faster. Wait.  */ +	      lll_futex_wait (once_control, newval, LLL_PRIVATE); +	      continue; +	    } +	} + +      /* This thread is the first here.  Do the initialization. +	 Register a cleanup handler so that in case the thread gets +	 interrupted the initialization can be restarted.  */ +      pthread_cleanup_push (clear_once_control, once_control); + +      init_routine (); + +      pthread_cleanup_pop (0); + + +      /* Add one to *once_control.  */ +      atomic_increment (once_control); + +      /* Wake up all other threads.  */ +      lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE); +      break; +    } + +  return 0; +} +weak_alias (__pthread_once, pthread_once) +strong_alias (__pthread_once, __pthread_once_internal) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h new file mode 100644 index 000000000..1cf625f4e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h @@ -0,0 +1,188 @@ +/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +# ifdef __PIC__ +#  define PSEUDO_CPLOAD .cpload t9; +#  define PSEUDO_ERRJMP la t9, __syscall_error; jr t9; +#  define PSEUDO_SAVEGP sw gp, 32(sp); cfi_rel_offset (gp, 32); +#  define PSEUDO_LOADGP lw gp, 32(sp); +# else +#  define PSEUDO_CPLOAD +#  define PSEUDO_ERRJMP j __syscall_error; +#  define PSEUDO_SAVEGP +#  define PSEUDO_LOADGP +# endif + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args)				      \ +      .align 2;								      \ +  L(pseudo_start):							      \ +      cfi_startproc;							      \ +  99: PSEUDO_ERRJMP							      \ +  .type __##syscall_name##_nocancel, @function;				      \ +  .globl __##syscall_name##_nocancel;					      \ +  __##syscall_name##_nocancel:						      \ +    .set noreorder;							      \ +    PSEUDO_CPLOAD							      \ +    li v0, SYS_ify(syscall_name);					      \ +    syscall;								      \ +    .set reorder;							      \ +    bne a3, zero, 99b;					       		      \ +    ret;								      \ +  .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;	      \ +  ENTRY (name)								      \ +    .set noreorder;							      \ +    PSEUDO_CPLOAD							      \ +    .set reorder;							      \ +    SINGLE_THREAD_P(v1);						      \ +    bne zero, v1, L(pseudo_cancel);					      \ +    .set noreorder;							      \ +    li v0, SYS_ify(syscall_name);					      \ +    syscall;								      \ +    .set reorder;							      \ +    bne a3, zero, 99b;					       		      \ +    ret;								      \ +  L(pseudo_cancel):							      \ +    SAVESTK_##args;						              \ +    sw ra, 28(sp);							      \ +    cfi_rel_offset (ra, 28);						      \ +    PSEUDO_SAVEGP							      \ +    PUSHARGS_##args;			/* save syscall args */	      	      \ +    CENABLE;								      \ +    PSEUDO_LOADGP							      \ +    sw v0, 44(sp);			/* save mask */			      \ +    POPARGS_##args;			/* restore syscall args */	      \ +    .set noreorder;							      \ +    li v0, SYS_ify (syscall_name);				      	      \ +    syscall;								      \ +    .set reorder;							      \ +    sw v0, 36(sp);			/* save syscall result */             \ +    sw a3, 40(sp);			/* save syscall error flag */	      \ +    lw a0, 44(sp);			/* pass mask as arg1 */		      \ +    CDISABLE;								      \ +    PSEUDO_LOADGP							      \ +    lw v0, 36(sp);			/* restore syscall result */          \ +    lw a3, 40(sp);			/* restore syscall error flag */      \ +    lw ra, 28(sp);			/* restore return address */	      \ +    .set noreorder;							      \ +    bne a3, zero, 99b;							      \ +     RESTORESTK;						              \ +  L(pseudo_end):							      \ +    .set reorder; + +# undef PSEUDO_END +# define PSEUDO_END(sym) cfi_endproc; .end sym; .size sym,.-sym + +# define PUSHARGS_0	/* nothing to do */ +# define PUSHARGS_1	PUSHARGS_0 sw a0, 0(sp); cfi_rel_offset (a0, 0); +# define PUSHARGS_2	PUSHARGS_1 sw a1, 4(sp); cfi_rel_offset (a1, 4); +# define PUSHARGS_3	PUSHARGS_2 sw a2, 8(sp); cfi_rel_offset (a2, 8); +# define PUSHARGS_4	PUSHARGS_3 sw a3, 12(sp); cfi_rel_offset (a3, 12); +# define PUSHARGS_5	PUSHARGS_4 /* handled by SAVESTK_## */ +# define PUSHARGS_6	PUSHARGS_5 +# define PUSHARGS_7	PUSHARGS_6 + +# define POPARGS_0	/* nothing to do */ +# define POPARGS_1	POPARGS_0 lw a0, 0(sp); +# define POPARGS_2	POPARGS_1 lw a1, 4(sp); +# define POPARGS_3	POPARGS_2 lw a2, 8(sp); +# define POPARGS_4	POPARGS_3 lw a3, 12(sp); +# define POPARGS_5	POPARGS_4 /* args already in new stackframe */ +# define POPARGS_6	POPARGS_5 +# define POPARGS_7	POPARGS_6 + + +# define STKSPACE	48 +# define SAVESTK_0 	subu sp, STKSPACE; cfi_adjust_cfa_offset(STKSPACE) +# define SAVESTK_1      SAVESTK_0 +# define SAVESTK_2      SAVESTK_1 +# define SAVESTK_3      SAVESTK_2 +# define SAVESTK_4      SAVESTK_3 +# define SAVESTK_5      lw t0, 16(sp);		\ +			SAVESTK_0;		\ +			sw t0, 16(sp) + +# define SAVESTK_6      lw t0, 16(sp);		\ +			lw t1, 20(sp);		\ +			SAVESTK_0;		\ +			sw t0, 16(sp);		\ +			sw t1, 20(sp) + +# define SAVESTK_7      lw t0, 16(sp);		\ +			lw t1, 20(sp);		\ +			lw t2, 24(sp);		\ +			SAVESTK_0;		\ +			sw t0, 16(sp);		\ +			sw t1, 20(sp);		\ +			sw t2, 24(sp) + +# define RESTORESTK 	addu sp, STKSPACE; cfi_adjust_cfa_offset(-STKSPACE) + + +# ifdef __PIC__ +/* We use jalr rather than jal.  This means that the assembler will not +   automatically restore $gp (in case libc has multiple GOTs) so we must +   do it manually - which we have to do anyway since we don't use .cprestore. +   It also shuts up the assembler warning about not using .cprestore.  */ +#  define PSEUDO_JMP(sym) la t9, sym; jalr t9; +# else +#  define PSEUDO_JMP(sym) jal sym; +# endif + +# ifdef IS_IN_libpthread +#  define CENABLE	PSEUDO_JMP (__pthread_enable_asynccancel) +#  define CDISABLE	PSEUDO_JMP (__pthread_disable_asynccancel) +# elif defined IS_IN_librt +#  define CENABLE	PSEUDO_JMP (__librt_enable_asynccancel) +#  define CDISABLE	PSEUDO_JMP (__librt_disable_asynccancel) +# else +#  define CENABLE	PSEUDO_JMP (__libc_enable_asynccancel) +#  define CDISABLE	PSEUDO_JMP (__libc_disable_asynccancel) +# endif + +# ifndef __ASSEMBLER__ +#  define SINGLE_THREAD_P						\ +	__builtin_expect (THREAD_GETMEM (THREAD_SELF,			\ +					 header.multiple_threads)	\ +			  == 0, 1) +# else +#  define SINGLE_THREAD_P(reg)						\ +	READ_THREAD_POINTER(reg);					\ +	lw reg, MULTIPLE_THREADS_OFFSET(reg) +#endif + +#elif !defined __ASSEMBLER__ + +# define SINGLE_THREAD_P 1 +# define NO_CANCELLATION 1 + +#endif + +#ifndef __ASSEMBLER__ +# define RTLD_SINGLE_THREAD_P \ +  __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ +				   header.multiple_threads) == 0, 1) +#endif | 
