diff options
Diffstat (limited to 'libpthread/nptl/sysdeps/unix/sysv/linux/mips')
13 files changed, 1165 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..f112b8a39 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h @@ -0,0 +1,215 @@ +/* Machine-specific pthread type layouts.  MIPS version. +   Copyright (C) 2005 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H	1 + +#include <sgidefs.h> + +#if _MIPS_SIM == _ABI64 +# define __SIZEOF_PTHREAD_ATTR_T 56 +# define __SIZEOF_PTHREAD_MUTEX_T 40 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 56 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 32 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#else +# define __SIZEOF_PTHREAD_ATTR_T 36 +# define __SIZEOF_PTHREAD_MUTEX_T 24 +# define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +# define __SIZEOF_PTHREAD_COND_T 48 +# define __SIZEOF_PTHREAD_CONDATTR_T 4 +# define __SIZEOF_PTHREAD_RWLOCK_T 32 +# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +# define __SIZEOF_PTHREAD_BARRIER_T 20 +# define __SIZEOF_PTHREAD_BARRIERATTR_T 4 +#endif + + +/* Thread identifiers.  The structure of the attribute type is +   deliberately not exposed.  */ +typedef unsigned long int pthread_t; + + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_ATTR_T]; +  long int __align; +} pthread_attr_t; + +#if _MIPS_SIM == _ABI64 +typedef struct __pthread_internal_list +{ +  struct __pthread_internal_list *__prev; +  struct __pthread_internal_list *__next; +} __pthread_list_t; +#else +typedef struct __pthread_internal_slist +{ +  struct __pthread_internal_slist *__next; +} __pthread_slist_t; +#endif + +/* Data structures for mutex handling.  The structure of the attribute +   type is deliberately not exposed.  */ +typedef union +{ +  struct __pthread_mutex_s +  { +    int __lock; +    unsigned int __count; +    int __owner; +#if _MIPS_SIM == _ABI64 +    unsigned int __nusers; +#endif +    /* KIND must stay at this position in the structure to maintain +       binary compatibility.  */ +    int __kind; +#if _MIPS_SIM == _ABI64 +    int __spins; +    __pthread_list_t __list; +# define __PTHREAD_MUTEX_HAVE_PREV      1 +#else +    unsigned int __nusers; +    __extension__ union +    { +      int __spins; +      __pthread_slist_t __list; +    }; +#endif +  } __data; +  char __size[__SIZEOF_PTHREAD_MUTEX_T]; +  long int __align; +} pthread_mutex_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; +  int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling.  The structure of +   the attribute type is deliberately not exposed.  */ +typedef union +{ +  struct +  { +    int __lock; +    unsigned int __futex; +    __extension__ unsigned long long int __total_seq; +    __extension__ unsigned long long int __wakeup_seq; +    __extension__ unsigned long long int __woken_seq; +    void *__mutex; +    unsigned int __nwaiters; +    unsigned int __broadcast_seq; +  } __data; +  char __size[__SIZEOF_PTHREAD_COND_T]; +  __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_CONDATTR_T]; +  int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling.  The +   structure of the attribute type is deliberately not exposed.  */ +typedef union +{ +# if _MIPS_SIM == _ABI64 +  struct +  { +    int __lock; +    unsigned int __nr_readers; +    unsigned int __readers_wakeup; +    unsigned int __writer_wakeup; +    unsigned int __nr_readers_queued; +    unsigned int __nr_writers_queued; +    int __writer; +    int __pad1; +    unsigned long int __pad2; +    unsigned long int __pad3; +    /* FLAGS must stay at this position in the structure to maintain +       binary compatibility.  */ +    unsigned int __flags; +  } __data; +# else +  struct +  { +    int __lock; +    unsigned int __nr_readers; +    unsigned int __readers_wakeup; +    unsigned int __writer_wakeup; +    unsigned int __nr_readers_queued; +    unsigned int __nr_writers_queued; +    /* FLAGS must stay at this position in the structure to maintain +       binary compatibility.  */ +    unsigned int __flags; +    int __writer; +  } __data; +# endif +  char __size[__SIZEOF_PTHREAD_RWLOCK_T]; +  long int __align; +} pthread_rwlock_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; +  long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type.  */ +typedef volatile int pthread_spinlock_t; + + +/* POSIX barriers data type.  The structure of the type is +   deliberately not exposed.  */ +typedef union +{ +  char __size[__SIZEOF_PTHREAD_BARRIER_T]; +  long int __align; +} pthread_barrier_t; + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; +  int __align; +} pthread_barrierattr_t; +#endif + + +#endif	/* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h new file mode 100644 index 000000000..c4440f9e9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2002, 2005 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _SEMAPHORE_H +# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead." +#endif + +#if _MIPS_SIM == _ABI64 +# define __SIZEOF_SEM_T	32 +#else +# define __SIZEOF_SEM_T	16 +#endif + +/* Value returned if `sem_open' failed.  */ +#define SEM_FAILED      ((sem_t *) 0) + +/* Maximum value the semaphore can have.  */ +#define SEM_VALUE_MAX   (2147483647) + + +typedef union +{ +  char __size[__SIZEOF_SEM_T]; +  long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/createthread.c new file mode 100644 index 000000000..d8a7c5539 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/createthread.c @@ -0,0 +1,24 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +/* Value passed to 'clone' for initialization of the thread register.  */ +#define TLS_VALUE ((void *) (pd) \ +		   + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE) + +/* Get the real implementation.	 */ +#include <sysdeps/pthread/createthread.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/fork.c new file mode 100644 index 000000000..06b7e1c69 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/fork.c @@ -0,0 +1 @@ +#include "../i386/fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h new file mode 100644 index 000000000..7edb28794 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h @@ -0,0 +1,216 @@ +/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H	1 + +#include <time.h> +#include <sys/param.h> +#include <bits/pthreadtypes.h> +#include <atomic.h> +#include <sysdep.h> + + +#define FUTEX_WAIT		0 +#define FUTEX_WAKE		1 +#define FUTEX_REQUEUE		3 +#define FUTEX_CMP_REQUEUE	4 + +/* Initializer for compatibility lock.	*/ +#define LLL_MUTEX_LOCK_INITIALIZER (0) + +#define lll_futex_wait(futexp, val) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4,				      \ +			      (futexp), FUTEX_WAIT, (val), 0);		      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;		      \ +  }) + +#define lll_futex_timed_wait(futexp, val, timespec) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4,				      \ +			      (futexp), FUTEX_WAIT, (val), (timespec));	      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;		      \ +  }) + +#define lll_futex_wake(futexp, nr) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 4,				      \ +			      (futexp), FUTEX_WAKE, (nr), 0);		      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret;		      \ +  }) + +/* Returns non-zero if error happened, zero if success.  */ +#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val) \ +  ({									      \ +    INTERNAL_SYSCALL_DECL (__err);					      \ +    long int __ret;							      \ +    __ret = INTERNAL_SYSCALL (futex, __err, 6,				      \ +			      (futexp), FUTEX_CMP_REQUEUE, (nr_wake),	      \ +			      (nr_move), (mutex), (val));		      \ +    INTERNAL_SYSCALL_ERROR_P (__ret, __err);				      \ +  }) + + +static inline int __attribute__((always_inline)) +__lll_mutex_trylock(int *futex) +{ +  return atomic_compare_and_exchange_val_acq (futex, 1, 0) != 0; +} +#define lll_mutex_trylock(lock)	__lll_mutex_trylock (&(lock)) + + +static inline int __attribute__((always_inline)) +__lll_mutex_cond_trylock(int *futex) +{ +  return atomic_compare_and_exchange_val_acq (futex, 2, 0) != 0; +} +#define lll_mutex_cond_trylock(lock)	__lll_mutex_cond_trylock (&(lock)) + + +extern void __lll_lock_wait (int *futex) attribute_hidden; + +static inline void __attribute__((always_inline)) +__lll_mutex_lock(int *futex) +{ +  if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0) +    __lll_lock_wait (futex); +} +#define lll_mutex_lock(futex) __lll_mutex_lock (&(futex)) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_cond_lock (int *futex) +{ +  if (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0) +    __lll_lock_wait (futex); +} +#define lll_mutex_cond_lock(futex) __lll_mutex_cond_lock (&(futex)) + + +extern int __lll_timedlock_wait (int *futex, const struct timespec *) +	attribute_hidden; + +static inline int __attribute__ ((always_inline)) +__lll_mutex_timedlock (int *futex, const struct timespec *abstime) +{ +  int result = 0; +  if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0) +    result = __lll_timedlock_wait (futex, abstime); +  return result; +} +#define lll_mutex_timedlock(futex, abstime) \ +  __lll_mutex_timedlock (&(futex), abstime) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_unlock (int *futex) +{ +  int val = atomic_exchange_rel (futex, 0); +  if (__builtin_expect (val > 1, 0)) +    lll_futex_wake (futex, 1); +} +#define lll_mutex_unlock(futex) __lll_mutex_unlock(&(futex)) + + +static inline void __attribute__ ((always_inline)) +__lll_mutex_unlock_force (int *futex) +{ +  (void) atomic_exchange_rel (futex, 0); +  lll_futex_wake (futex, 1); +} +#define lll_mutex_unlock_force(futex) __lll_mutex_unlock_force(&(futex)) + + +#define lll_mutex_islocked(futex) \ +  (futex != 0) + + +/* Our internal lock implementation is identical to the binary-compatible +   mutex implementation. */ + +/* Type for lock object.  */ +typedef int lll_lock_t; + +/* Initializers for lock.  */ +#define LLL_LOCK_INITIALIZER		(0) +#define LLL_LOCK_INITIALIZER_LOCKED	(1) + +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + +/* The states of a lock are: +    0  -  untaken +    1  -  taken by one user +   >1  -  taken by more users */ + +#define lll_trylock(lock)	lll_mutex_trylock (lock) +#define lll_lock(lock)		lll_mutex_lock (lock) +#define lll_unlock(lock)	lll_mutex_unlock (lock) +#define lll_islocked(lock)	lll_mutex_islocked (lock) + +/* The kernel notifies a process which uses CLONE_CLEARTID via futex +   wakeup when the clone terminates.  The memory location contains the +   thread ID while the clone is running and is reset to zero +   afterwards.	*/ +#define lll_wait_tid(tid) \ +  do {					\ +    __typeof (tid) __tid;		\ +    while ((__tid = (tid)) != 0)	\ +      lll_futex_wait (&(tid), __tid);	\ +  } while (0) + +extern int __lll_timedwait_tid (int *, const struct timespec *) +     attribute_hidden; + +#define lll_timedwait_tid(tid, abstime) \ +  ({							\ +    int __res = 0;					\ +    if ((tid) != 0)					\ +      __res = __lll_timedwait_tid (&(tid), (abstime));	\ +    __res;						\ +  }) + + +/* Conditional variable handling.  */ + +extern void __lll_cond_wait (pthread_cond_t *cond) +     attribute_hidden; +extern int __lll_cond_timedwait (pthread_cond_t *cond, +				 const struct timespec *abstime) +     attribute_hidden; +extern void __lll_cond_wake (pthread_cond_t *cond) +     attribute_hidden; +extern void __lll_cond_broadcast (pthread_cond_t *cond) +     attribute_hidden; + +#define lll_cond_wait(cond) \ +  __lll_cond_wait (cond) +#define lll_cond_timedwait(cond, abstime) \ +  __lll_cond_timedwait (cond, abstime) +#define lll_cond_wake(cond) \ +  __lll_cond_wake (cond) +#define lll_cond_broadcast(cond) \ +  __lll_cond_broadcast (cond) + +#endif	/* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-__syscall_rt_sigaction.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-__syscall_rt_sigaction.c new file mode 100644 index 000000000..50137c84a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-__syscall_rt_sigaction.c @@ -0,0 +1 @@ +#include <../../../../../../../libc/sysdeps/linux/common/__syscall_rt_sigaction.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-clone.S new file mode 100644 index 000000000..add405523 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-clone.S @@ -0,0 +1,2 @@ +#define RESET_PID +#include <../../../../../../../libc/sysdeps/linux/mips/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S new file mode 100644 index 000000000..c02ffca93 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S @@ -0,0 +1,38 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <features.h> +#include <tls.h> + +/* Save the PID value.  */ +#define SAVE_PID \ +	READ_THREAD_POINTER(v1);	/* Get the thread pointer.  */	\ +	lw	a2, PID_OFFSET(v1);	/* Load the saved PID.  */	\ +	subu	a2, $0, a2;		/* Negate it.  */		\ +	sw	a2, PID_OFFSET(v1);	/* Store the temporary PID.  */ + +/* Restore the old PID value in the parent.  */ +#define RESTORE_PID \ +	beqz	v0, 1f;			/* If we are the parent... */	\ +	READ_THREAD_POINTER(v1);	/* Get the thread pointer.  */	\ +	lw	a2, PID_OFFSET(v1);	/* Load the saved PID.  */	\ +	subu	a2, $0, a2;		/* Re-negate it.  */		\ +	sw	a2, PID_OFFSET(v1);	/* Restore the PID.  */		\ +1: + +#include <../../../../../../../libc/sysdeps/linux/mips/vfork.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c new file mode 100644 index 000000000..649b752f5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c @@ -0,0 +1,94 @@ +/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include "pthreadP.h" +#include <lowlevellock.h> + + +unsigned long int __fork_generation attribute_hidden; + + +static void +clear_once_control (void *arg) +{ +  pthread_once_t *once_control = (pthread_once_t *) arg; + +  *once_control = 0; +  lll_futex_wake (once_control, INT_MAX); +} + + +int +__pthread_once (once_control, init_routine) +     pthread_once_t *once_control; +     void (*init_routine) (void); +{ +  while (1) +    { +      int oldval, val, newval; + +      val = *once_control; +      do +	{ +	  /* Check if the initialized has already been done.  */ +	  if ((val & 2) != 0) +	    return 0; + +	  oldval = val; +	  newval = (oldval & 3) | __fork_generation | 1; +	  val = atomic_compare_and_exchange_val_acq (once_control, newval, +						     oldval); +	} +      while (__builtin_expect (val != oldval, 0)); + +      /* Check if another thread already runs the initializer.	*/ +      if ((oldval & 1) != 0) +	{ +	  /* Check whether the initializer execution was interrupted +	     by a fork.	 */ +	  if (((oldval ^ newval) & -4) == 0) +	    { +	      /* Same generation, some other thread was faster. Wait.  */ +	      lll_futex_wait (once_control, newval); +	      continue; +	    } +	} + +      /* This thread is the first here.  Do the initialization. +	 Register a cleanup handler so that in case the thread gets +	 interrupted the initialization can be restarted.  */ +      pthread_cleanup_push (clear_once_control, once_control); + +      init_routine (); + +      pthread_cleanup_pop (0); + + +      /* Add one to *once_control.  */ +      atomic_increment (once_control); + +      /* Wake up all other threads.  */ +      lll_futex_wake (once_control, INT_MAX); +      break; +    } + +  return 0; +} +weak_alias (__pthread_once, pthread_once) +strong_alias (__pthread_once, __pthread_once_internal) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h new file mode 100644 index 000000000..5fee89235 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h @@ -0,0 +1,169 @@ +/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <tls.h> +#ifndef __ASSEMBLER__ +# include <pthreadP.h> +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +#ifdef __PIC__ +# undef PSEUDO +# define PSEUDO(name, syscall_name, args)				      \ +      .align 2;								      \ +  L(pseudo_start):							      \ +      cfi_startproc;							      \ +  99: la t9,__syscall_error;						      \ +      jr t9;								      \ +  .type __##syscall_name##_nocancel, @function;				      \ +  .globl __##syscall_name##_nocancel;					      \ +  __##syscall_name##_nocancel:						      \ +    .set noreorder;							      \ +    .cpload t9;								      \ +    li v0, SYS_ify(syscall_name);					      \ +    syscall;								      \ +    .set reorder;							      \ +    bne a3, zero, SYSCALL_ERROR_LABEL;			       		      \ +    ret;								      \ +  .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;	      \ +  ENTRY (name)								      \ +    .set noreorder;							      \ +    .cpload t9;								      \ +    .set reorder;							      \ +    SINGLE_THREAD_P(v1);						      \ +    bne zero, v1, L(pseudo_cancel);					      \ +    .set noreorder;							      \ +    li v0, SYS_ify(syscall_name);					      \ +    syscall;								      \ +    .set reorder;							      \ +    bne a3, zero, SYSCALL_ERROR_LABEL;			       		      \ +    ret;								      \ +  L(pseudo_cancel):							      \ +    SAVESTK_##args;						              \ +    sw ra, 28(sp);							      \ +    cfi_rel_offset (ra, 28);						      \ +    sw gp, 32(sp);							      \ +    cfi_rel_offset (gp, 32);						      \ +    PUSHARGS_##args;			/* save syscall args */	      	      \ +    CENABLE;								      \ +    lw gp, 32(sp);							      \ +    sw v0, 44(sp);			/* save mask */			      \ +    POPARGS_##args;			/* restore syscall args */	      \ +    .set noreorder;							      \ +    li v0, SYS_ify (syscall_name);				      	      \ +    syscall;								      \ +    .set reorder;							      \ +    sw v0, 36(sp);			/* save syscall result */             \ +    sw a3, 40(sp);			/* save syscall error flag */	      \ +    lw a0, 44(sp);			/* pass mask as arg1 */		      \ +    CDISABLE;								      \ +    lw gp, 32(sp);							      \ +    lw v0, 36(sp);			/* restore syscall result */          \ +    lw a3, 40(sp);			/* restore syscall error flag */      \ +    lw ra, 28(sp);			/* restore return address */	      \ +    .set noreorder;							      \ +    bne a3, zero, SYSCALL_ERROR_LABEL;					      \ +     RESTORESTK;						              \ +  L(pseudo_end):							      \ +    .set reorder; + +# undef PSEUDO_END +# define PSEUDO_END(sym) cfi_endproc; .end sym; .size sym,.-sym + +#endif + +# define PUSHARGS_0	/* nothing to do */ +# define PUSHARGS_1	PUSHARGS_0 sw a0, 0(sp); cfi_rel_offset (a0, 0); +# define PUSHARGS_2	PUSHARGS_1 sw a1, 4(sp); cfi_rel_offset (a1, 4); +# define PUSHARGS_3	PUSHARGS_2 sw a2, 8(sp); cfi_rel_offset (a2, 8); +# define PUSHARGS_4	PUSHARGS_3 sw a3, 12(sp); cfi_rel_offset (a3, 12); +# define PUSHARGS_5	PUSHARGS_4 /* handled by SAVESTK_## */ +# define PUSHARGS_6	PUSHARGS_5 +# define PUSHARGS_7	PUSHARGS_6 + +# define POPARGS_0	/* nothing to do */ +# define POPARGS_1	POPARGS_0 lw a0, 0(sp); +# define POPARGS_2	POPARGS_1 lw a1, 4(sp); +# define POPARGS_3	POPARGS_2 lw a2, 8(sp); +# define POPARGS_4	POPARGS_3 lw a3, 12(sp); +# define POPARGS_5	POPARGS_4 /* args already in new stackframe */ +# define POPARGS_6	POPARGS_5 +# define POPARGS_7	POPARGS_6 + + +# define STKSPACE	48 +# define SAVESTK_0 	subu sp, STKSPACE; cfi_adjust_cfa_offset(STKSPACE) +# define SAVESTK_1      SAVESTK_0 +# define SAVESTK_2      SAVESTK_1 +# define SAVESTK_3      SAVESTK_2 +# define SAVESTK_4      SAVESTK_3 +# define SAVESTK_5      lw t0, 16(sp);		\ +			SAVESTK_0;		\ +			sw t0, 16(sp) + +# define SAVESTK_6      lw t0, 16(sp);		\ +			lw t1, 20(sp);		\ +			SAVESTK_0;		\ +			sw t0, 16(sp);		\ +			sw t1, 20(sp) + +# define SAVESTK_7      lw t0, 16(sp);		\ +			lw t1, 20(sp);		\ +			lw t2, 24(sp);		\ +			SAVESTK_0;		\ +			sw t0, 16(sp);		\ +			sw t1, 20(sp);		\ +			sw t2, 24(sp) + +# define RESTORESTK 	addu sp, STKSPACE; cfi_adjust_cfa_offset(-STKSPACE) + + +/* We use jalr rather than jal.  This means that the assembler will not +   automatically restore $gp (in case libc has multiple GOTs) so we must +   do it manually - which we have to do anyway since we don't use .cprestore. +   It also shuts up the assembler warning about not using .cprestore.  */ +# ifdef IS_IN_libpthread +#  define CENABLE	la t9, __pthread_enable_asynccancel; jalr t9; +#  define CDISABLE	la t9, __pthread_disable_asynccancel; jalr t9; +# elif defined IS_IN_librt +#  define CENABLE	la t9, __librt_enable_asynccancel; jalr t9; +#  define CDISABLE	la t9, __librt_disable_asynccancel; jalr t9; +# else +#  define CENABLE	la t9, __libc_enable_asynccancel; jalr t9; +#  define CDISABLE	la t9, __libc_disable_asynccancel; jalr t9; +# endif + +# ifndef __ASSEMBLER__ +#  define SINGLE_THREAD_P						\ +	__builtin_expect (THREAD_GETMEM (THREAD_SELF,			\ +					 header.multiple_threads)	\ +			  == 0, 1) +# else +#  define SINGLE_THREAD_P(reg)						\ +	READ_THREAD_POINTER(reg);					\ +	lw reg, MULTIPLE_THREADS_OFFSET(reg) +#endif + +#elif !defined __ASSEMBLER__ + +# define SINGLE_THREAD_P 1 +# define NO_CANCELLATION 1 + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep.h new file mode 100644 index 000000000..bfaab1f3a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep.h @@ -0,0 +1,302 @@ +/* Copyright (C) 2000, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. +   This file is part of the GNU C Library. + +   The GNU C Library is free software; you can redistribute it and/or +   modify it under the terms of the GNU Lesser General Public +   License as published by the Free Software Foundation; either +   version 2.1 of the License, or (at your option) any later version. + +   The GNU C Library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +   Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public +   License along with the GNU C Library; if not, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#ifndef _LINUX_MIPS_MIPS32_SYSDEP_H +#define _LINUX_MIPS_MIPS32_SYSDEP_H 1 + +#include <sys/syscall.h> + +/* There is some commonality.  */ +#include <sysdeps/mips/sysdep.h> + +/* For Linux we can use the system call table in the header file +	/usr/include/asm/unistd.h +   of the kernel.  But these symbols do not follow the SYS_* syntax +   so we have to redefine the `SYS_ify' macro here.  */ +#undef SYS_ify +#ifdef __STDC__ +# define SYS_ify(syscall_name)	__NR_##syscall_name +#else +# define SYS_ify(syscall_name)	__NR_/**/syscall_name +#endif + +#ifdef __ASSEMBLER__ + +/* We don't want the label for the error handler to be visible in the symbol +   table when we define it here.  */ +#ifdef __PIC__ +# define SYSCALL_ERROR_LABEL 99b +#endif + +#else   /* ! __ASSEMBLER__ */ + +/* Define a macro which expands into the inline wrapper code for a system +   call.  */ +#undef INLINE_SYSCALL +#define INLINE_SYSCALL(name, nr, args...)                               \ +  ({ INTERNAL_SYSCALL_DECL(err);					\ +     long result_var = INTERNAL_SYSCALL (name, err, nr, args);		\ +     if ( INTERNAL_SYSCALL_ERROR_P (result_var, err) )			\ +       {								\ +	 __set_errno (INTERNAL_SYSCALL_ERRNO (result_var, err));	\ +	 result_var = -1L;						\ +       }								\ +     result_var; }) + +#undef INTERNAL_SYSCALL_DECL +#define INTERNAL_SYSCALL_DECL(err) long err + +#undef INTERNAL_SYSCALL_ERROR_P +#define INTERNAL_SYSCALL_ERROR_P(val, err)   ((long) (err)) + +#undef INTERNAL_SYSCALL_ERRNO +#define INTERNAL_SYSCALL_ERRNO(val, err)     (val) + +#undef INTERNAL_SYSCALL +#define INTERNAL_SYSCALL(name, err, nr, args...) \ +	internal_syscall##nr (, "li\t$2, %2\t\t\t# " #name "\n\t",	\ +			      "i" (SYS_ify (name)), err, args) + +#undef INTERNAL_SYSCALL_NCS +#define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \ +	internal_syscall##nr (= number, , "r" (__v0), err, args) +#undef internal_syscall0 +#define internal_syscall0(ncs_init, cs_init, input, err, dummy...)	\ +({									\ +	long _sys_result;						\ +									\ +	{								\ +	register long __v0 __asm__("$2") ncs_init;			\ +	register long __a3 __asm__("$7");				\ +	__asm__ volatile (						\ +	".set\tnoreorder\n\t"						\ +	cs_init								\ +	"syscall\n\t"							\ +	".set reorder"							\ +	: "=r" (__v0), "=r" (__a3)					\ +	: input								\ +	: __SYSCALL_CLOBBERS);						\ +	err = __a3;							\ +	_sys_result = __v0;						\ +	}								\ +	_sys_result;							\ +}) + +#undef internal_syscall1 +#define internal_syscall1(ncs_init, cs_init, input, err, arg1)		\ +({									\ +	long _sys_result;						\ +									\ +	{								\ +	register long __v0 __asm__("$2") ncs_init;			\ +	register long __a0 __asm__("$4") = (long) arg1;			\ +	register long __a3 __asm__("$7");				\ +	__asm__ volatile (						\ +	".set\tnoreorder\n\t"						\ +	cs_init								\ +	"syscall\n\t"							\ +	".set reorder"							\ +	: "=r" (__v0), "=r" (__a3)					\ +	: input, "r" (__a0)						\ +	: __SYSCALL_CLOBBERS);						\ +	err = __a3;							\ +	_sys_result = __v0;						\ +	}								\ +	_sys_result;							\ +}) + +#undef internal_syscall2 +#define internal_syscall2(ncs_init, cs_init, input, err, arg1, arg2)	\ +({									\ +	long _sys_result;						\ +									\ +	{								\ +	register long __v0 __asm__("$2") ncs_init;			\ +	register long __a0 __asm__("$4") = (long) arg1;			\ +	register long __a1 __asm__("$5") = (long) arg2;			\ +	register long __a3 __asm__("$7");				\ +	__asm__ volatile (						\ +	".set\tnoreorder\n\t"						\ +	cs_init								\ +	"syscall\n\t"							\ +	".set\treorder"							\ +	: "=r" (__v0), "=r" (__a3)					\ +	: input, "r" (__a0), "r" (__a1)					\ +	: __SYSCALL_CLOBBERS);						\ +	err = __a3;							\ +	_sys_result = __v0;						\ +	}								\ +	_sys_result;							\ +}) + +#undef internal_syscall3 +#define internal_syscall3(ncs_init, cs_init, input, err, arg1, arg2, arg3)\ +({									\ +	long _sys_result;						\ +									\ +	{								\ +	register long __v0 __asm__("$2") ncs_init;			\ +	register long __a0 __asm__("$4") = (long) arg1;			\ +	register long __a1 __asm__("$5") = (long) arg2;			\ +	register long __a2 __asm__("$6") = (long) arg3;			\ +	register long __a3 __asm__("$7");				\ +	__asm__ volatile (						\ +	".set\tnoreorder\n\t"						\ +	cs_init								\ +	"syscall\n\t"							\ +	".set\treorder"							\ +	: "=r" (__v0), "=r" (__a3)					\ +	: input, "r" (__a0), "r" (__a1), "r" (__a2)			\ +	: __SYSCALL_CLOBBERS);						\ +	err = __a3;							\ +	_sys_result = __v0;						\ +	}								\ +	_sys_result;							\ +}) + +#undef internal_syscall4 +#define internal_syscall4(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4)\ +({									\ +	long _sys_result;						\ +									\ +	{								\ +	register long __v0 __asm__("$2") ncs_init;			\ +	register long __a0 __asm__("$4") = (long) arg1;			\ +	register long __a1 __asm__("$5") = (long) arg2;			\ +	register long __a2 __asm__("$6") = (long) arg3;			\ +	register long __a3 __asm__("$7") = (long) arg4;			\ +	__asm__ volatile (						\ +	".set\tnoreorder\n\t"						\ +	cs_init								\ +	"syscall\n\t"							\ +	".set\treorder"							\ +	: "=r" (__v0), "+r" (__a3)					\ +	: input, "r" (__a0), "r" (__a1), "r" (__a2)			\ +	: __SYSCALL_CLOBBERS);						\ +	err = __a3;							\ +	_sys_result = __v0;						\ +	}								\ +	_sys_result;							\ +}) + +/* We need to use a frame pointer for the functions in which we +   adjust $sp around the syscall, or debug information and unwind +   information will be $sp relative and thus wrong during the syscall.  As +   of GCC 3.4.3, this is sufficient.  */ +#define FORCE_FRAME_POINTER alloca (4) + +#undef internal_syscall5 +#define internal_syscall5(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5)\ +({									\ +	long _sys_result;						\ +									\ +	FORCE_FRAME_POINTER;						\ +	{								\ +	register long __v0 __asm__("$2") ncs_init;			\ +	register long __a0 __asm__("$4") = (long) arg1;			\ +	register long __a1 __asm__("$5") = (long) arg2;			\ +	register long __a2 __asm__("$6") = (long) arg3;			\ +	register long __a3 __asm__("$7") = (long) arg4;			\ +	__asm__ volatile (						\ +	".set\tnoreorder\n\t"						\ +	"subu\t$29, 32\n\t"						\ +	"sw\t%6, 16($29)\n\t"						\ +	cs_init								\ +	"syscall\n\t"							\ +	"addiu\t$29, 32\n\t"						\ +	".set\treorder"							\ +	: "=r" (__v0), "+r" (__a3)					\ +	: input, "r" (__a0), "r" (__a1), "r" (__a2),			\ +	  "r" ((long)arg5)						\ +	: __SYSCALL_CLOBBERS);						\ +	err = __a3;							\ +	_sys_result = __v0;						\ +	}								\ +	_sys_result;							\ +}) + +#undef internal_syscall6 +#define internal_syscall6(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5, arg6)\ +({									\ +	long _sys_result;						\ +									\ +	FORCE_FRAME_POINTER;						\ +	{								\ +	register long __v0 __asm__("$2") ncs_init;			\ +	register long __a0 __asm__("$4") = (long) arg1;			\ +	register long __a1 __asm__("$5") = (long) arg2;			\ +	register long __a2 __asm__("$6") = (long) arg3;			\ +	register long __a3 __asm__("$7") = (long) arg4;			\ +	__asm__ volatile (						\ +	".set\tnoreorder\n\t"						\ +	"subu\t$29, 32\n\t"						\ +	"sw\t%6, 16($29)\n\t"						\ +	"sw\t%7, 20($29)\n\t"						\ +	cs_init								\ +	"syscall\n\t"							\ +	"addiu\t$29, 32\n\t"						\ +	".set\treorder"							\ +	: "=r" (__v0), "+r" (__a3)					\ +	: input, "r" (__a0), "r" (__a1), "r" (__a2),			\ +	  "r" ((long)arg5), "r" ((long)arg6)				\ +	: __SYSCALL_CLOBBERS);						\ +	err = __a3;							\ +	_sys_result = __v0;						\ +	}								\ +	_sys_result;							\ +}) + +#undef internal_syscall7 +#define internal_syscall7(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5, arg6, arg7)\ +({									\ +	long _sys_result;						\ +									\ +	FORCE_FRAME_POINTER;						\ +	{								\ +	register long __v0 __asm__("$2") ncs_init;			\ +	register long __a0 __asm__("$4") = (long) arg1;			\ +	register long __a1 __asm__("$5") = (long) arg2;			\ +	register long __a2 __asm__("$6") = (long) arg3;			\ +	register long __a3 __asm__("$7") = (long) arg4;			\ +	__asm__ volatile (						\ +	".set\tnoreorder\n\t"						\ +	"subu\t$29, 32\n\t"						\ +	"sw\t%6, 16($29)\n\t"						\ +	"sw\t%7, 20($29)\n\t"						\ +	"sw\t%8, 24($29)\n\t"						\ +	cs_init								\ +	"syscall\n\t"							\ +	"addiu\t$29, 32\n\t"						\ +	".set\treorder"							\ +	: "=r" (__v0), "+r" (__a3)					\ +	: input, "r" (__a0), "r" (__a1), "r" (__a2),			\ +	  "r" ((long)arg5), "r" ((long)arg6), "r" ((long)arg7)		\ +	: __SYSCALL_CLOBBERS);						\ +	err = __a3;							\ +	_sys_result = __v0;						\ +	}								\ +	_sys_result;							\ +}) + +#undef __SYSCALL_CLOBBERS +#define __SYSCALL_CLOBBERS "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", \ +	"$14", "$15", "$24", "$25", "memory" + +#endif /* __ASSEMBLER__ */ + +#endif /* sysdeps/unix/sysv/linux/mips/sysdep.h */ | 
