Update.
authorAndreas Jaeger <aj@suse.de>
Mon, 28 Mar 2005 09:26:46 +0000 (09:26 +0000)
committerAndreas Jaeger <aj@suse.de>
Mon, 28 Mar 2005 09:26:46 +0000 (09:26 +0000)
* sysdeps/mips/atomicity.h: Remove unused file.
* sysdeps/mips/dl-machine.h (elf_machine_rel): Add TLS relocations.
* sysdeps/mips/dl-tls.h: New file.
* sysdeps/mips/libc-tls.c: New file.
* sysdeps/mips/tls-macros.h: New file.
* sysdeps/mips/bits/atomic.h: New file.
* sysdeps/mips/bits/setjmp.h: Protect against multiple inclusion.
* sysdeps/mips/elf/configure.in: New file.
* sysdeps/mips/elf/configure: Generated.
* sysdeps/mips/sys/asm.h: New file.
* sysdeps/unix/sysv/linux/mips/vfork.S: New file.
* sysdeps/unix/sysv/linux/mips/clone.S: Add NPTL and five-argument
clone support.
* sysdeps/unix/sysv/linux/mips/mips32/sysdep.h
(INTERNAL_SYSCALL_NCS): New.
(INTERNAL_SYSCALL): Update for non-constant support.
(internal_syscall0): Likewise.
(internal_syscall1): Likewise.
(internal_syscall2): Likewise.
(internal_syscall3): Likewise.
(internal_syscall4): Likewise.
(internal_syscall5): Likewise.
(internal_syscall6): Likewise.
(internal_syscall7): Likewise.
* sysdeps/unix/sysv/linux/mips/bits/siginfo.h (SIGEV_THREAD):
Update to match the kernel.
(SIGEV_CALLBACK): Likewise.
(SIGEV_THREAD_ID): Likewise.

2005-03-28  Daniel Jacobowitz  <dan@codesourcery.com>

35 files changed:
ChangeLog
linuxthreads/ChangeLog
linuxthreads/sysdeps/mips/tls.h [new file with mode: 0644]
linuxthreads/sysdeps/unix/sysv/linux/mips/vfork.S [new file with mode: 0644]
nptl/ChangeLog
nptl/sysdeps/mips/Makefile [new file with mode: 0644]
nptl/sysdeps/mips/jmpbuf-unwind.h [new file with mode: 0644]
nptl/sysdeps/mips/nptl-sysdep.S [new file with mode: 0644]
nptl/sysdeps/mips/pthread_spin_lock.S [new file with mode: 0644]
nptl/sysdeps/mips/pthread_spin_trylock.S [new file with mode: 0644]
nptl/sysdeps/mips/pthreaddef.h [new file with mode: 0644]
nptl/sysdeps/mips/tcb-offsets.sym [new file with mode: 0644]
nptl/sysdeps/mips/tls.h [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/mips/clone.S [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/mips/createthread.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/mips/fork.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/mips/vfork.S [new file with mode: 0644]
sysdeps/mips/atomicity.h [deleted file]
sysdeps/mips/bits/atomic.h [new file with mode: 0644]
sysdeps/mips/dl-tls.h [new file with mode: 0644]
sysdeps/mips/dl-trampoline.c
sysdeps/mips/elf/configure [new file with mode: 0644]
sysdeps/mips/elf/configure.in [new file with mode: 0644]
sysdeps/mips/libc-tls.c [new file with mode: 0644]
sysdeps/mips/sys/asm.h
sysdeps/mips/tls-macros.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/mips/bits/siginfo.h
sysdeps/unix/sysv/linux/mips/clone.S
sysdeps/unix/sysv/linux/mips/mips32/sysdep.h
sysdeps/unix/sysv/linux/mips/vfork.S [new file with mode: 0644]

index 48d7dea..966cb82 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,36 @@
 2005-03-28  Daniel Jacobowitz  <dan@codesourcery.com>
 
+       * sysdeps/mips/atomicity.h: Remove unused file.
+       * sysdeps/mips/dl-machine.h (elf_machine_rel): Add TLS relocations.
+       * sysdeps/mips/dl-tls.h: New file.
+       * sysdeps/mips/libc-tls.c: New file.
+       * sysdeps/mips/tls-macros.h: New file.
+       * sysdeps/mips/bits/atomic.h: New file.
+       * sysdeps/mips/bits/setjmp.h: Protect against multiple inclusion.
+       * sysdeps/mips/elf/configure.in: New file.
+       * sysdeps/mips/elf/configure: Generated.
+       * sysdeps/mips/sys/asm.h: New file.
+       * sysdeps/unix/sysv/linux/mips/vfork.S: New file.
+       * sysdeps/unix/sysv/linux/mips/clone.S: Add NPTL and five-argument
+       clone support.
+       * sysdeps/unix/sysv/linux/mips/mips32/sysdep.h
+       (INTERNAL_SYSCALL_NCS): New.
+       (INTERNAL_SYSCALL): Update for non-constant support.
+       (internal_syscall0): Likewise.
+       (internal_syscall1): Likewise.
+       (internal_syscall2): Likewise.
+       (internal_syscall3): Likewise.
+       (internal_syscall4): Likewise.
+       (internal_syscall5): Likewise.
+       (internal_syscall6): Likewise.
+       (internal_syscall7): Likewise.
+       * sysdeps/unix/sysv/linux/mips/bits/siginfo.h (SIGEV_THREAD):
+       Update to match the kernel.
+       (SIGEV_CALLBACK): Likewise.
+       (SIGEV_THREAD_ID): Likewise.
+
+2005-03-28  Daniel Jacobowitz  <dan@codesourcery.com>
+
        [BZ #783]
        * elf/tst-auditmod1.c: Add MIPS support.
        * sysdeps/generic/ldsodefs.h (La_mips_32_regs): New.
index bf84281..dfecefc 100644 (file)
@@ -1,3 +1,8 @@
+2005-03-28  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * sysdeps/mips/tls.h: New file.
+       * sysdeps/unix/sysv/linux/mips/vfork.S: New file.
+
 2005-03-21  GOTO Masanori  <gotom@debian.or.jp>
 
        * linuxthreads/sysdeps/m68k/Makefile: Remove to delete
diff --git a/linuxthreads/sysdeps/mips/tls.h b/linuxthreads/sysdeps/mips/tls.h
new file mode 100644 (file)
index 0000000..be4478d
--- /dev/null
@@ -0,0 +1,170 @@
+/* Definitions for thread-local data handling.  linuxthreads/MIPS version.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _TLS_H
+#define _TLS_H
+
+#ifndef __ASSEMBLER__
+
+# include <stdbool.h>
+# include <pt-machine.h>
+# include <stddef.h>
+
+/* Type for the dtv.  */
+typedef union dtv
+{
+  size_t counter;
+  struct
+  {
+    void *val;
+    bool is_static;
+  } pointer;
+} dtv_t;
+
+# define READ_THREAD_POINTER() \
+    ({ void *__result;                                                       \
+       asm volatile (".set\tpush\n\t.set\tmips32r2\n\t"                              \
+                    "rdhwr\t%0, $29\n\t.set\tpop" : "=v" (__result));        \
+       __result; })
+
+#else /* __ASSEMBLER__ */
+# include <tcb-offsets.h>
+
+/* Note: rd must be $v1 to be ABI-conformant.  */
+# define READ_THREAD_POINTER(rd) \
+       .set    push;                                                         \
+       .set    mips32r2;                                                     \
+       rdhwr   rd, $29;                                                      \
+       .set    pop
+#endif /* __ASSEMBLER__ */
+
+/* LinuxThreads can only use TLS if both floating stacks (in the MIPS case,
+   that means support for "rdhwr") and support from the tools are available.
+
+   We have to define USE_TLS consistently, or ldsodefs.h will lay out types
+   differently between an NPTL build and a LinuxThreads build.  It can be set
+   for libc.so and not libpthread.so, but only if we provide appropriate padding
+   in the _pthread_descr_struct.
+
+   Currently nothing defines FLOATING_STACKS.  We could assume this based on
+   kernel version once the TLS patches are available in kernel.org, but
+   it hardly seems worth it.  Use NPTL if you can.
+
+   To avoid bothering with the TLS support code at all, use configure
+   --without-tls.  */
+
+#if defined HAVE_TLS_SUPPORT \
+    && (defined FLOATING_STACKS || !defined IS_IN_libpthread)
+
+/* Signal that TLS support is available.  */
+# define USE_TLS       1
+
+/* Include padding in _pthread_descr_struct so that libc can find p_errno,
+   if libpthread will only include the padding because of the !IS_IN_libpthread
+   check.  */
+#ifndef FLOATING_STACKS
+# define INCLUDE_TLS_PADDING   1
+#endif
+
+# ifndef __ASSEMBLER__
+
+/* This layout is actually wholly private and not affected by the ABI.
+   Nor does it overlap the pthread data structure, so we need nothing
+   extra here at all.  */
+typedef struct
+{
+  dtv_t *dtv;
+  void *private;
+} tcbhead_t;
+
+/* This is the size of the initial TCB.  */
+#  define TLS_INIT_TCB_SIZE    0
+
+/* Alignment requirements for the initial TCB.  */
+#  define TLS_INIT_TCB_ALIGN   __alignof__ (struct _pthread_descr_struct)
+
+/* This is the size of the TCB.  */
+#  define TLS_TCB_SIZE         0
+
+/* Alignment requirements for the TCB.  */
+#  define TLS_TCB_ALIGN                __alignof__ (struct _pthread_descr_struct)
+
+/* This is the size we need before TCB.  */
+#  define TLS_PRE_TCB_SIZE \
+  (sizeof (struct _pthread_descr_struct)                                     \
+   + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1)))
+
+/* The thread pointer (in hardware register $29) points to the end of
+   the TCB + 0x7000, as for PowerPC.  The pthread_descr structure is
+   immediately in front of the TCB.  */
+#define TLS_TCB_OFFSET         0x7000
+
+/* The DTV is allocated at the TP; the TCB is placed elsewhere.  */
+/* This is not really true for powerpc64.  We are following alpha
+   where the DTV pointer is first doubleword in the TCB.  */
+#  define TLS_DTV_AT_TP 1
+
+/* Install the dtv pointer.  The pointer passed is to the element with
+   index -1 which contain the length.  */
+#  define INSTALL_DTV(TCBP, DTVP) \
+  (((tcbhead_t *) (TCBP))[-1].dtv = (DTVP) + 1)
+
+/* Install new dtv for current thread.  */
+#  define INSTALL_NEW_DTV(DTV) (THREAD_DTV() = (DTV))
+
+/* Return dtv of given thread descriptor.  */
+#  define GET_DTV(TCBP)        (((tcbhead_t *) (TCBP))[-1].dtv)
+
+/* Code to initially initialize the thread pointer.  This might need
+   special attention since 'errno' is not yet available and if the
+   operation can cause a failure 'errno' must not be touched.  */
+# define TLS_INIT_TP(tcbp, secondcall) \
+  ({ INTERNAL_SYSCALL_DECL (err);                                      \
+     long result_var;                                                  \
+     result_var = INTERNAL_SYSCALL (set_thread_area, err, 1,           \
+                                   (char *) (tcbp) + TLS_TCB_OFFSET);  \
+     INTERNAL_SYSCALL_ERROR_P (result_var, err)                                \
+       ? "unknown error" : NULL; })
+
+/* Return the address of the dtv for the current thread.  */
+# define THREAD_DTV() \
+  (((tcbhead_t *) (READ_THREAD_POINTER () - TLS_TCB_OFFSET))[-1].dtv)
+
+/* Return the thread descriptor for the current thread.  */
+#  undef THREAD_SELF
+#  define THREAD_SELF \
+    ((pthread_descr) (READ_THREAD_POINTER () \
+                     - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE))
+
+/* Get the thread descriptor definition.  */
+#  include <linuxthreads/descr.h>
+
+/* l_tls_offset == 0 is perfectly valid on MIPS, so we have to use some
+   different value to mean unset l_tls_offset.  */
+#  define NO_TLS_OFFSET        -1
+
+/* Initializing the thread pointer requires a syscall which may not be
+   available, so don't do it if we don't need to.  */
+#  define TLS_INIT_TP_EXPENSIVE 1
+
+# endif /* __ASSEMBLER__ */
+
+#endif /* HAVE_TLS_SUPPORT */
+
+#endif /* tls.h */
diff --git a/linuxthreads/sysdeps/unix/sysv/linux/mips/vfork.S b/linuxthreads/sysdeps/unix/sysv/linux/mips/vfork.S
new file mode 100644 (file)
index 0000000..bf54143
--- /dev/null
@@ -0,0 +1,104 @@
+/* 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.  */
+
+/* vfork() is just a special case of clone().  */
+
+#include <sys/asm.h>
+#include <sysdep.h>
+#include <asm/unistd.h>
+
+/* int vfork() */
+
+       .text
+LOCALSZ= 1
+FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK
+GPOFF= FRAMESZ-(1*SZREG)
+NESTED(__vfork,FRAMESZ,sp)
+#ifdef __PIC__
+       SETUP_GP
+#endif
+       PTR_SUBU sp, FRAMESZ
+       SETUP_GP64 (a5, __vfork)
+#ifdef __PIC__
+       SAVE_GP (GPOFF)
+#endif
+#ifdef PROF
+# if (_MIPS_SIM != _ABIO32)
+       PTR_S           a5, GPOFF(sp)
+# endif
+       .set            noat
+       move            $1, ra
+# if (_MIPS_SIM == _ABIO32)
+       subu            sp,sp,8
+# endif
+       jal             _mcount
+       .set            at
+# if (_MIPS_SIM != _ABIO32)
+       PTR_L           a5, GPOFF(sp)
+# endif
+#endif
+
+       /* If libpthread is loaded, we need to call fork instead.  */
+#ifdef SHARED
+       PTR_L           a0, __libc_pthread_functions
+#else
+       .weak           pthread_create
+       PTR_LA          a0, pthread_create
+#endif
+
+       PTR_ADDU        sp, FRAMESZ
+
+       bnez            a0, L(call_fork)
+
+       li              a0, 0x4112      /* CLONE_VM | CLONE_VFORK | SIGCHLD */
+       move            a1, sp
+
+       /* Do the system call */
+       li              v0,__NR_clone
+       syscall
+
+       bnez            a3,L(error)
+
+       /* Successful return from the parent or child.  */
+       RESTORE_GP64
+       ret
+
+       /* Something bad happened -- no child created.  */
+L(error):
+#ifdef __PIC__
+       PTR_LA          t9, __syscall_error
+       RESTORE_GP64
+       jr              t9
+#else
+       RESTORE_GP64
+       j               __syscall_error
+#endif
+
+L(call_fork):
+#ifdef __PIC__
+       PTR_LA          t9, fork
+       RESTORE_GP64
+       jr              t9
+#else
+       RESTORE_GP64
+       j               fork
+#endif
+       END(__vfork)
+
+libc_hidden_def(__vfork)
+weak_alias(__vfork, vfork)
index 23b0f51..82895d4 100644 (file)
@@ -1,3 +1,24 @@
+2005-03-28  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * sysdeps/mips/Makefile: New file.
+       * sysdeps/mips/nptl-sysdep.S: New file.
+       * sysdeps/mips/tcb-offsets.sym: New file.
+       * sysdeps/mips/pthread_spin_lock.S: New file.
+       * sysdeps/mips/pthread_spin_trylock.S: New file.
+       * sysdeps/mips/pthreaddef.h: New file.
+       * sysdeps/mips/tls.h: New file.
+       * sysdeps/mips/jmpbuf-unwind.h: New file.
+       * sysdeps/unix/sysv/linux/mips/lowlevellock.h: New file.
+       * sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h: New file.
+       * sysdeps/unix/sysv/linux/mips/bits/semaphore.h: New file.
+       * sysdeps/unix/sysv/linux/mips/pthread_once.c: New file.
+       * sysdeps/unix/sysv/linux/mips/fork.c: New file.
+       * sysdeps/unix/sysv/linux/mips/pt-vfork.S: New file.
+       * sysdeps/unix/sysv/linux/mips/vfork.S: New file.
+       * sysdeps/unix/sysv/linux/mips/clone.S: New file.
+       * sysdeps/unix/sysv/linux/mips/createthread.c: New file.
+       * sysdeps/unix/sysv/linux/mips/sysdep-cancel.h: New file.
+
 2005-03-23  Ulrich Drepper  <drepper@redhat.com>
 
        * pthread_create.c (__pthread_create_2_1): Rename syscall error
diff --git a/nptl/sysdeps/mips/Makefile b/nptl/sysdeps/mips/Makefile
new file mode 100644 (file)
index 0000000..d0c59a5
--- /dev/null
@@ -0,0 +1,25 @@
+# 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.
+
+ifeq ($(subdir),csu)
+gen-as-const-headers += tcb-offsets.sym
+endif
+
+ifeq ($(subdir),nptl)
+libpthread-sysdep_routines += nptl-sysdep
+endif
diff --git a/nptl/sysdeps/mips/jmpbuf-unwind.h b/nptl/sysdeps/mips/jmpbuf-unwind.h
new file mode 100644 (file)
index 0000000..67cc969
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <setjmp.h>
+#include <stdint.h>
+#include <unwind.h>
+
+#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \
+  _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj)
+
+#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \
+  ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[0].__sp - (_adj))
+
+/* We use the normal longjmp for unwinding.  */
+#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val)
diff --git a/nptl/sysdeps/mips/nptl-sysdep.S b/nptl/sysdeps/mips/nptl-sysdep.S
new file mode 100644 (file)
index 0000000..3f5c2a3
--- /dev/null
@@ -0,0 +1,2 @@
+/* Pull in __syscall_error.  */
+#include <sysdep.S>
diff --git a/nptl/sysdeps/mips/pthread_spin_lock.S b/nptl/sysdeps/mips/pthread_spin_lock.S
new file mode 100644 (file)
index 0000000..d5f2a72
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sys/asm.h>
+#include <sysdep.h>
+#include <sgidefs.h>
+
+ENTRY (pthread_spin_lock)
+       .set    push
+#if _MIPS_SIM == _ABIO32
+       .set    mips2
+#endif
+1:     ll      a2, 0(a0)
+       li      a1, 1
+       bnez    a2, 1b
+       sc      a1, 0(a0)
+       beqz    a1, 1b
+       MIPS_SYNC
+       .set    pop
+       li      v0, 0
+       ret
+PSEUDO_END (pthread_spin_lock)
diff --git a/nptl/sysdeps/mips/pthread_spin_trylock.S b/nptl/sysdeps/mips/pthread_spin_trylock.S
new file mode 100644 (file)
index 0000000..9c6e740
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sys/asm.h>
+#include <sysdep.h>
+#define _ERRNO_H 1
+#include <bits/errno.h>
+#include <sgidefs.h>
+
+ENTRY (pthread_spin_trylock)
+       .set    push
+#if _MIPS_SIM == _ABIO32
+       .set    mips2
+#endif
+       ll      a2, 0(a0)
+       li      a1, 1
+       bnez    a2, 1f
+       sc      a1, 0(a0)
+       beqz    a1, 1f
+       MIPS_SYNC
+       .set    pop
+       li      v0, 0
+       ret
+1:     li      v0, EBUSY
+       ret
+PSEUDO_END (pthread_spin_trylock)
diff --git a/nptl/sysdeps/mips/pthreaddef.h b/nptl/sysdeps/mips/pthreaddef.h
new file mode 100644 (file)
index 0000000..e72b4bc
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Default stack size.  */
+#define ARCH_STACK_DEFAULT_SIZE        (2 * 1024 * 1024)
+
+/* Required stack pointer alignment at beginning.  */
+#define STACK_ALIGN            16
+
+/* Minimal stack size after allocating thread descriptor and guard size.  */
+#define MINIMAL_REST_STACK     2048
+
+/* Alignment requirement for TCB.  */
+#define TCB_ALIGNMENT          16
+
+
+/* Location of current stack frame.  */
+#define CURRENT_STACK_FRAME    __builtin_frame_address (0)
+
+
+/* XXX Until we have a better place keep the definitions here.  */
+
+#define __exit_thread_inline(val) \
+  INLINE_SYSCALL (exit, 1, (val))
diff --git a/nptl/sysdeps/mips/tcb-offsets.sym b/nptl/sysdeps/mips/tcb-offsets.sym
new file mode 100644 (file)
index 0000000..e0e71dc
--- /dev/null
@@ -0,0 +1,11 @@
+#include <sysdep.h>
+#include <tls.h>
+
+--
+
+-- Abuse tls.h macros to derive offsets relative to the thread register.
+#define thread_offsetof(mem)   (long)(offsetof(struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)
+
+MULTIPLE_THREADS_OFFSET                thread_offsetof (header.multiple_threads)
+PID_OFFSET                     thread_offsetof (pid)
+TID_OFFSET                     thread_offsetof (tid)
diff --git a/nptl/sysdeps/mips/tls.h b/nptl/sysdeps/mips/tls.h
new file mode 100644 (file)
index 0000000..1cef161
--- /dev/null
@@ -0,0 +1,161 @@
+/* Definition for thread-local data handling.  NPTL/MIPS version.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _TLS_H
+#define _TLS_H 1
+
+#include <dl-sysdep.h>
+
+#ifndef __ASSEMBLER__
+# include <stdbool.h>
+# include <stddef.h>
+# include <stdint.h>
+
+/* Type for the dtv.  */
+typedef union dtv
+{
+  size_t counter;
+  struct
+  {
+    void *val;
+    bool is_static;
+  } pointer;
+} dtv_t;
+
+/* Note: rd must be $v1 to be ABI-conformant.  */
+# define READ_THREAD_POINTER() \
+    ({ void *__result;                                                       \
+       asm volatile (".set\tpush\n\t.set\tmips32r2\n\t"                              \
+                    "rdhwr\t%0, $29\n\t.set\tpop" : "=v" (__result));        \
+       __result; })
+
+#else /* __ASSEMBLER__ */
+# include <tcb-offsets.h>
+
+# define READ_THREAD_POINTER(rd) \
+       .set    push;                                                         \
+       .set    mips32r2;                                                     \
+       rdhwr   rd, $29;                                                      \
+       .set    pop
+#endif /* __ASSEMBLER__ */
+
+
+/* We require TLS support in the tools.  */
+#ifndef HAVE_TLS_SUPPORT
+# error "TLS support is required."
+#endif
+
+/* Signal that TLS support is available.  */
+#define USE_TLS        1
+
+#ifndef __ASSEMBLER__
+
+/* Get system call information.  */
+# include <sysdep.h>
+
+/* The TP points to the start of the thread blocks.  */
+# define TLS_DTV_AT_TP 1
+
+/* Get the thread descriptor definition.  */
+# include <nptl/descr.h>
+
+typedef struct
+{
+  dtv_t *dtv;
+  void *private;
+} tcbhead_t;
+
+/* This is the size of the initial TCB.  Because our TCB is before the thread
+   pointer, we don't need this.  */
+# define TLS_INIT_TCB_SIZE     0
+
+/* Alignment requirements for the initial TCB.  */
+# define TLS_INIT_TCB_ALIGN    __alignof__ (struct pthread)
+
+/* This is the size of the TCB.  Because our TCB is before the thread
+   pointer, we don't need this.  */
+# define TLS_TCB_SIZE          0
+
+/* Alignment requirements for the TCB.  */
+# define TLS_TCB_ALIGN         __alignof__ (struct pthread)
+
+/* This is the size we need before TCB - actually, it includes the TCB.  */
+# define TLS_PRE_TCB_SIZE \
+  (sizeof (struct pthread)                                                   \
+   + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1)))
+
+/* The thread pointer (in hardware register $29) points to the end of
+   the TCB + 0x7000, as for PowerPC.  The pthread_descr structure is
+   immediately in front of the TCB.  */
+# define TLS_TCB_OFFSET        0x7000
+
+/* Install the dtv pointer.  The pointer passed is to the element with
+   index -1 which contain the length.  */
+# define INSTALL_DTV(tcbp, dtvp) \
+  (((tcbhead_t *) (tcbp))[-1].dtv = (dtvp) + 1)
+
+/* Install new dtv for current thread.  */
+# define INSTALL_NEW_DTV(dtv) \
+  (THREAD_DTV() = (dtv))
+
+/* Return dtv of given thread descriptor.  */
+# define GET_DTV(tcbp) \
+  (((tcbhead_t *) (tcbp))[-1].dtv)
+
+/* Code to initially initialize the thread pointer.  This might need
+   special attention since 'errno' is not yet available and if the
+   operation can cause a failure 'errno' must not be touched.  */
+# define TLS_INIT_TP(tcbp, secondcall) \
+  ({ INTERNAL_SYSCALL_DECL (err);                                      \
+     long result_var;                                                  \
+     result_var = INTERNAL_SYSCALL (set_thread_area, err, 1,           \
+                                   (char *) (tcbp) + TLS_TCB_OFFSET);  \
+     INTERNAL_SYSCALL_ERROR_P (result_var, err)                                \
+       ? "unknown error" : NULL; })
+
+/* Return the address of the dtv for the current thread.  */
+# define THREAD_DTV() \
+  (((tcbhead_t *) (READ_THREAD_POINTER () - TLS_TCB_OFFSET))[-1].dtv)
+
+/* Return the thread descriptor for the current thread.  */
+# define THREAD_SELF \
+ ((struct pthread *) (READ_THREAD_POINTER ()                        \
+                     - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE))
+
+/* Magic for libthread_db to know how to do THREAD_SELF.  */
+# define DB_THREAD_SELF \
+  CONST_THREAD_AREA (32, TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE)
+
+/* Access to data in the thread descriptor is easy.  */
+# define THREAD_GETMEM(descr, member) \
+  descr->member
+# define THREAD_GETMEM_NC(descr, member, idx) \
+  descr->member[idx]
+# define THREAD_SETMEM(descr, member, value) \
+  descr->member = (value)
+# define THREAD_SETMEM_NC(descr, member, idx, value) \
+  descr->member[idx] = (value)
+
+/* l_tls_offset == 0 is perfectly valid on MIPS, so we have to use some
+   different value to mean unset l_tls_offset.  */
+# define NO_TLS_OFFSET         -1
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* tls.h */
diff --git a/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h b/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h
new file mode 100644 (file)
index 0000000..c4440f9
--- /dev/null
@@ -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/nptl/sysdeps/unix/sysv/linux/mips/clone.S b/nptl/sysdeps/unix/sysv/linux/mips/clone.S
new file mode 100644 (file)
index 0000000..80c265b
--- /dev/null
@@ -0,0 +1,2 @@
+#define RESET_PID
+#include <sysdeps/unix/sysv/linux/mips/clone.S>
diff --git a/nptl/sysdeps/unix/sysv/linux/mips/createthread.c b/nptl/sysdeps/unix/sysv/linux/mips/createthread.c
new file mode 100644 (file)
index 0000000..5b2234f
--- /dev/null
@@ -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 <nptl/sysdeps/pthread/createthread.c>
diff --git a/nptl/sysdeps/unix/sysv/linux/mips/fork.c b/nptl/sysdeps/unix/sysv/linux/mips/fork.c
new file mode 100644 (file)
index 0000000..06b7e1c
--- /dev/null
@@ -0,0 +1 @@
+#include "../i386/fork.c"
diff --git a/nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h b/nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h
new file mode 100644 (file)
index 0000000..7edb287
--- /dev/null
@@ -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/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S b/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S
new file mode 100644 (file)
index 0000000..fe2b81b
--- /dev/null
@@ -0,0 +1,37 @@
+/* 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 <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 <../sysdeps/unix/sysv/linux/mips/vfork.S>
diff --git a/nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c b/nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c
new file mode 100644 (file)
index 0000000..649b752
--- /dev/null
@@ -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/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h b/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h
new file mode 100644 (file)
index 0000000..02508e2
--- /dev/null
@@ -0,0 +1,170 @@
+/* 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 <sysdeps/generic/sysdep.h>
+#include <tls.h>
+#ifndef __ASSEMBLER__
+# include <nptl/pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+#ifdef __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/nptl/sysdeps/unix/sysv/linux/mips/vfork.S b/nptl/sysdeps/unix/sysv/linux/mips/vfork.S
new file mode 100644 (file)
index 0000000..874a2e2
--- /dev/null
@@ -0,0 +1,42 @@
+/* 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 <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.  */               \
+       bnez    a2, 1f;                 /* If it was zero... */         \
+       lui     a2, 0x8000;             /* use 0x80000000 instead.  */  \
+1:     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.  */            \
+       lui     a0, 0x8000;             /* Load 0x80000000... */        \
+       bne     a2, a0, 2f;             /* ... compare against it... */ \
+       li      a2, 0;                  /* ... use 0 instead.  */       \
+2:     sw      a2, PID_OFFSET(v1);     /* Restore the PID.  */         \
+1:
+
+#include <../sysdeps/unix/sysv/linux/mips/vfork.S>
diff --git a/sysdeps/mips/atomicity.h b/sysdeps/mips/atomicity.h
deleted file mode 100644 (file)
index 7380e10..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/* Low-level functions for atomic operations. Mips version.
-   Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
-
-#ifndef _MIPS_ATOMICITY_H
-#define _MIPS_ATOMICITY_H    1
-
-#include <inttypes.h>
-#include <sgidefs.h>
-
-static inline int
-__attribute__ ((unused))
-exchange_and_add (volatile uint32_t *mem, int val)
-{
-  int result, tmp;
-
-  __asm__ __volatile__
-    ("/* Inline exchange & add */\n"
-     "1:\n\t"
-     ".set     push\n\t"
-#if _MIPS_SIM == _ABIO32
-     ".set     mips2\n\t"
-#endif
-     "ll       %0,%3\n\t"
-     "addu     %1,%4,%0\n\t"
-     "sc       %1,%2\n\t"
-     ".set     pop\n\t"
-     "beqz     %1,1b\n\t"
-     "/* End exchange & add */"
-     : "=&r"(result), "=&r"(tmp), "=m"(*mem)
-     : "m" (*mem), "r"(val)
-     : "memory");
-
-  return result;
-}
-
-static inline void
-__attribute__ ((unused))
-atomic_add (volatile uint32_t *mem, int val)
-{
-  int result;
-
-  __asm__ __volatile__
-    ("/* Inline atomic add */\n"
-     "1:\n\t"
-     ".set     push\n\t"
-#if _MIPS_SIM == _ABIO32
-     ".set     mips2\n\t"
-#endif
-     "ll       %0,%2\n\t"
-     "addu     %0,%3,%0\n\t"
-     "sc       %0,%1\n\t"
-     ".set     pop\n\t"
-     "beqz     %0,1b\n\t"
-     "/* End atomic add */"
-     : "=&r"(result), "=m"(*mem)
-     : "m" (*mem), "r"(val)
-     : "memory");
-}
-
-static inline int
-__attribute__ ((unused))
-compare_and_swap (volatile long int *p, long int oldval, long int newval)
-{
-  long int ret, temp;
-
-  __asm__ __volatile__
-    ("/* Inline compare & swap */\n"
-     "1:\n\t"
-     ".set     push\n\t"
-#if _MIPS_SIM == _ABIO32
-     ".set     mips2\n\t"
-#endif
-#if _MIPS_SIM == _ABI64
-     "lld      %1,%5\n\t"
-#else
-     "ll       %1,%5\n\t"
-#endif
-     "move     %0,$0\n\t"
-     "bne      %1,%3,2f\n\t"
-     "move     %0,%4\n\t"
-#if _MIPS_SIM == _ABI64
-     "scd      %0,%2\n\t"
-#else
-     "sc       %0,%2\n\t"
-#endif
-     ".set     pop\n\t"
-     "beqz     %0,1b\n"
-     "2:\n\t"
-     "/* End compare & swap */"
-     : "=&r" (ret), "=&r" (temp), "=m" (*p)
-     : "r" (oldval), "r" (newval), "m" (*p)
-     : "memory");
-
-  return ret;
-}
-
-#endif /* atomicity.h */
diff --git a/sysdeps/mips/bits/atomic.h b/sysdeps/mips/bits/atomic.h
new file mode 100644 (file)
index 0000000..167d9a5
--- /dev/null
@@ -0,0 +1,303 @@
+/* Low-level functions for atomic operations. 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 _MIPS_BITS_ATOMIC_H
+#define _MIPS_BITS_ATOMIC_H 1
+
+#include <inttypes.h>
+#include <sgidefs.h>
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef int64_t atomic64_t;
+typedef uint64_t uatomic64_t;
+typedef int_fast64_t atomic_fast64_t;
+typedef uint_fast64_t uatomic_fast64_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+#if _MIPS_SIM == _ABIO32
+#define MIPS_PUSH_MIPS2 ".set  mips2\n\t"
+#else
+#define MIPS_PUSH_MIPS2
+#endif
+
+/* See the comments in <sys/asm.h> about the use of the sync instruction.  */
+#ifndef MIPS_SYNC
+# define MIPS_SYNC     sync
+#endif
+
+#define MIPS_SYNC_STR_2(X) #X
+#define MIPS_SYNC_STR_1(X) MIPS_SYNC_STR_2(X)
+#define MIPS_SYNC_STR MIPS_SYNC_STR_1(MIPS_SYNC)
+
+/* Compare and exchange.  For all of the "xxx" routines, we expect a
+   "__prev" and a "__cmp" variable to be provided by the enclosing scope,
+   in which values are returned.  */
+
+#define __arch_compare_and_exchange_xxx_8_int(mem, newval, oldval, rel, acq) \
+  (abort (), __prev = __cmp = 0)
+
+#define __arch_compare_and_exchange_xxx_16_int(mem, newval, oldval, rel, acq) \
+  (abort (), __prev = __cmp = 0)
+
+#define __arch_compare_and_exchange_xxx_32_int(mem, newval, oldval, rel, acq) \
+     __asm__ __volatile__ (                                                  \
+     ".set     push\n\t"                                                     \
+     MIPS_PUSH_MIPS2                                                         \
+     rel       "\n"                                                          \
+     "1:\t"                                                                  \
+     "ll       %0,%4\n\t"                                                    \
+     "move     %1,$0\n\t"                                                    \
+     "bne      %0,%2,2f\n\t"                                                 \
+     "move     %1,%3\n\t"                                                    \
+     "sc       %1,%4\n\t"                                                    \
+     "beqz     %1,1b\n"                                                      \
+     acq       "\n\t"                                                        \
+     ".set     pop\n"                                                        \
+     "2:\n\t"                                                                \
+             : "=&r" (__prev), "=&r" (__cmp)                                 \
+             : "r" (oldval), "r" (newval), "m" (*mem)                        \
+             : "memory")
+
+#if _MIPS_SIM == _ABIO32
+/* We can't do an atomic 64-bit operation in O32.  */
+#define __arch_compare_and_exchange_xxx_64_int(mem, newval, oldval, rel, acq) \
+  (abort (), __prev = __cmp = 0)
+#else
+#define __arch_compare_and_exchange_xxx_64_int(mem, newval, oldval, rel, acq) \
+     __asm__ __volatile__ ("\n"                                                      \
+     ".set     push\n\t"                                                     \
+     MIPS_PUSH_MIPS2                                                         \
+     rel       "\n"                                                          \
+     "1:\t"                                                                  \
+     "lld      %0,%4\n\t"                                                    \
+     "move     %1,$0\n\t"                                                    \
+     "bne      %0,%2,2f\n\t"                                                 \
+     "move     %1,%3\n\t"                                                    \
+     "scd      %1,%4\n\t"                                                    \
+     "beqz     %1,1b\n"                                                      \
+     acq       "\n\t"                                                        \
+     ".set     pop\n"                                                        \
+     "2:\n\t"                                                                \
+             : "=&r" (__prev), "=&r" (__cmp)                                 \
+             : "r" (oldval), "r" (newval), "m" (*mem)                        \
+             : "memory")
+#endif
+
+/* For all "bool" routines, we return FALSE if exchange succesful.  */
+
+#define __arch_compare_and_exchange_bool_8_int(mem, new, old, rel, acq)        \
+({ typeof (*mem) __prev; int __cmp;                                    \
+   __arch_compare_and_exchange_xxx_8_int(mem, new, old, rel, acq);     \
+   !__cmp; })
+
+#define __arch_compare_and_exchange_bool_16_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;                                    \
+   __arch_compare_and_exchange_xxx_16_int(mem, new, old, rel, acq);    \
+   !__cmp; })
+
+#define __arch_compare_and_exchange_bool_32_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;                                    \
+   __arch_compare_and_exchange_xxx_32_int(mem, new, old, rel, acq);    \
+   !__cmp; })
+
+#define __arch_compare_and_exchange_bool_64_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;                                    \
+   __arch_compare_and_exchange_xxx_64_int(mem, new, old, rel, acq);    \
+   !__cmp; })
+
+/* For all "val" routines, return the old value whether exchange
+   successful or not.  */
+
+#define __arch_compare_and_exchange_val_8_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;                                    \
+   __arch_compare_and_exchange_xxx_8_int(mem, new, old, rel, acq);     \
+   (typeof (*mem))__prev; })
+
+#define __arch_compare_and_exchange_val_16_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;                                    \
+   __arch_compare_and_exchange_xxx_16_int(mem, new, old, rel, acq);    \
+   (typeof (*mem))__prev; })
+
+#define __arch_compare_and_exchange_val_32_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;                                    \
+   __arch_compare_and_exchange_xxx_32_int(mem, new, old, rel, acq);    \
+   (typeof (*mem))__prev; })
+
+#define __arch_compare_and_exchange_val_64_int(mem, new, old, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;                                    \
+   __arch_compare_and_exchange_xxx_64_int(mem, new, old, rel, acq);    \
+   (typeof (*mem))__prev; })
+
+/* Compare and exchange with "acquire" semantics, ie barrier after.  */
+
+#define atomic_compare_and_exchange_bool_acq(mem, new, old)    \
+  __atomic_bool_bysize (__arch_compare_and_exchange_bool, int, \
+                       mem, new, old, "", MIPS_SYNC_STR)
+
+#define atomic_compare_and_exchange_val_acq(mem, new, old)     \
+  __atomic_val_bysize (__arch_compare_and_exchange_val, int,   \
+                      mem, new, old, "", MIPS_SYNC_STR)
+
+/* Compare and exchange with "release" semantics, ie barrier before.  */
+
+#define atomic_compare_and_exchange_bool_rel(mem, new, old)    \
+  __atomic_bool_bysize (__arch_compare_and_exchange_bool, int, \
+                       mem, new, old, MIPS_SYNC_STR, "")
+
+#define atomic_compare_and_exchange_val_rel(mem, new, old)     \
+  __atomic_val_bysize (__arch_compare_and_exchange_val, int,   \
+                      mem, new, old, MIPS_SYNC_STR, "")
+
+
+
+/* Atomic exchange (without compare).  */
+
+#define __arch_exchange_xxx_8_int(mem, newval, rel, acq) \
+  (abort (), 0)
+
+#define __arch_exchange_xxx_16_int(mem, newval, rel, acq) \
+  (abort (), 0)
+
+#define __arch_exchange_xxx_32_int(mem, newval, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;                                          \
+     __asm__ __volatile__ ("\n"                                                      \
+     ".set     push\n\t"                                                     \
+     MIPS_PUSH_MIPS2                                                         \
+     rel       "\n"                                                          \
+     "1:\t"                                                                  \
+     "ll       %0,%3\n\t"                                                    \
+     "move     %1,%2\n\t"                                                    \
+     "sc       %1,%3\n\t"                                                    \
+     "beqz     %1,1b\n"                                                      \
+     acq       "\n\t"                                                        \
+     ".set     pop\n"                                                        \
+     "2:\n\t"                                                                \
+             : "=&r" (__prev), "=&r" (__cmp)                                 \
+             : "r" (newval), "m" (*mem)                                      \
+             : "memory");                                                    \
+  __prev; })
+
+#if _MIPS_SIM == _ABIO32
+/* We can't do an atomic 64-bit operation in O32.  */
+#define __arch_exchange_xxx_64_int(mem, newval, rel, acq) \
+  (abort (), 0)
+#else
+#define __arch_exchange_xxx_64_int(mem, newval, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;                                          \
+     __asm__ __volatile__ ("\n"                                                      \
+     ".set     push\n\t"                                                     \
+     MIPS_PUSH_MIPS2                                                         \
+     rel       "\n"                                                          \
+     "1:\n"                                                                  \
+     "lld      %0,%3\n\t"                                                    \
+     "move     %1,%2\n\t"                                                    \
+     "scd      %1,%3\n\t"                                                    \
+     "beqz     %1,1b\n"                                                      \
+     acq       "\n\t"                                                        \
+     ".set     pop\n"                                                        \
+     "2:\n\t"                                                                \
+             : "=&r" (__prev), "=&r" (__cmp)                                 \
+             : "r" (newval), "m" (*mem)                                      \
+             : "memory");                                                    \
+  __prev; })
+#endif
+
+#define atomic_exchange_acq(mem, value) \
+  __atomic_val_bysize (__arch_exchange_xxx, int, mem, value, "", MIPS_SYNC_STR)
+
+#define atomic_exchange_rel(mem, value) \
+  __atomic_val_bysize (__arch_exchange_xxx, int, mem, value, MIPS_SYNC_STR, "")
+
+
+/* Atomically add value and return the previous (unincremented) value.  */
+
+#define __arch_exchange_and_add_8_int(mem, newval, rel, acq) \
+  (abort (), (typeof(*mem)) 0)
+
+#define __arch_exchange_and_add_16_int(mem, newval, rel, acq) \
+  (abort (), (typeof(*mem)) 0)
+
+#define __arch_exchange_and_add_32_int(mem, value, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;                                          \
+     __asm__ __volatile__ ("\n"                                                      \
+     ".set     push\n\t"                                                     \
+     MIPS_PUSH_MIPS2                                                         \
+     rel       "\n"                                                          \
+     "1:\t"                                                                  \
+     "ll       %0,%3\n\t"                                                    \
+     "addu     %1,%0,%2\n\t"                                                 \
+     "sc       %1,%3\n\t"                                                    \
+     "beqz     %1,1b\n"                                                      \
+     acq       "\n\t"                                                        \
+     ".set     pop\n"                                                        \
+     "2:\n\t"                                                                \
+             : "=&r" (__prev), "=&r" (__cmp)                                 \
+             : "r" (value), "m" (*mem)                                       \
+             : "memory");                                                    \
+  __prev; })
+
+#if _MIPS_SIM == _ABIO32
+/* We can't do an atomic 64-bit operation in O32.  */
+#define __arch_exchange_and_add_64_int(mem, value, rel, acq) \
+  (abort (), (typeof(*mem)) 0)
+#else
+#define __arch_exchange_and_add_64_int(mem, value, rel, acq) \
+({ typeof (*mem) __prev; int __cmp;                                          \
+     __asm__ __volatile__ (                                                  \
+     ".set     push\n\t"                                                     \
+     MIPS_PUSH_MIPS2                                                         \
+     rel       "\n"                                                          \
+     "1:\t"                                                                  \
+     "lld      %0,%3\n\t"                                                    \
+     "daddu    %1,%0,%2\n\t"                                                 \
+     "scd      %1,%3\n\t"                                                    \
+     "beqz     %1,1b\n"                                                      \
+     acq       "\n\t"                                                        \
+     ".set     pop\n"                                                        \
+     "2:\n\t"                                                                \
+             : "=&r" (__prev), "=&r" (__cmp)                                 \
+             : "r" (value), "m" (*mem)                                       \
+             : "memory");                                                    \
+  __prev; })
+#endif
+
+/* ??? Barrier semantics for atomic_exchange_and_add appear to be 
+   undefined.  Use full barrier for now, as that's safe.  */
+#define atomic_exchange_and_add(mem, value) \
+  __atomic_val_bysize (__arch_exchange_and_add, int, mem, value,             \
+                      MIPS_SYNC_STR, MIPS_SYNC_STR)
+
+/* TODO: More atomic operations could be implemented efficiently; only the
+   basic requirements are done.  */
+
+#define atomic_full_barrier() \
+  __asm__ __volatile__ (".set push\n\t"                                              \
+                       MIPS_PUSH_MIPS2                                       \
+                       MIPS_SYNC_STR "\n\t"                                  \
+                       ".set pop" : : : "memory")
+
+#endif /* bits/atomic.h */
diff --git a/sysdeps/mips/dl-tls.h b/sysdeps/mips/dl-tls.h
new file mode 100644 (file)
index 0000000..6d3ed6f
--- /dev/null
@@ -0,0 +1,46 @@
+/* Thread-local storage handling in the ELF dynamic linker.  MIPS version.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+
+/* Type used for the representation of TLS information in the GOT.  */
+typedef struct
+{
+  unsigned long int ti_module;
+  unsigned long int ti_offset;
+} tls_index;
+
+/* The thread pointer points 0x7000 past the first static TLS block.  */
+#define TLS_TP_OFFSET          0x7000
+
+/* Dynamic thread vector pointers point 0x8000 past the start of each
+   TLS block.  */
+#define TLS_DTV_OFFSET         0x8000
+
+/* Compute the value for a GOTTPREL reloc.  */
+#define TLS_TPREL_VALUE(sym_map, sym) \
+  ((sym_map)->l_tls_offset + (sym)->st_value - TLS_TP_OFFSET)
+
+/* Compute the value for a DTPREL reloc.  */
+#define TLS_DTPREL_VALUE(sym) \
+  ((sym)->st_value - TLS_DTV_OFFSET)
+
+extern void *__tls_get_addr (tls_index *ti);
+
+# define GET_ADDR_OFFSET       (ti->ti_offset + TLS_DTV_OFFSET)
+# define __TLS_GET_ADDR(__ti)  (__tls_get_addr (__ti) - TLS_DTV_OFFSET)
index c5ea59c..459adf9 100644 (file)
@@ -153,7 +153,7 @@ __dl_runtime_resolve (ElfW(Word) sym_index,
 
            if (version->hash != 0)
              {
-               sym_map = _dl_lookup_symbol_x (strtab + sym->st_name, l, 
+               sym_map = _dl_lookup_symbol_x (strtab + sym->st_name, l,
                                               &sym, l->l_scope, version,
                                               ELF_RTYPE_CLASS_PLT, 0, 0);
                break;
diff --git a/sysdeps/mips/elf/configure b/sysdeps/mips/elf/configure
new file mode 100644 (file)
index 0000000..3d90a1e
--- /dev/null
@@ -0,0 +1,46 @@
+# This file is generated from configure.in by Autoconf.  DO NOT EDIT!
+ # Local configure fragment for sysdeps/mips/elf.
+
+if test "$usetls" != no; then
+# Check for support of thread-local storage handling in assembler and
+# linker.
+echo "$as_me:$LINENO: checking for MIPS TLS support" >&5
+echo $ECHO_N "checking for MIPS TLS support... $ECHO_C" >&6
+if test "${libc_cv_mips_tls+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat > conftest.s <<\EOF
+       .section ".tdata", "awT", %progbits
+       .globl foo
+foo:   .long   1
+       .section ".tbss", "awT", %nobits
+       .globl bar
+bar:   .skip   4
+       .text
+
+       lw      $25, %call16(__tls_get_addr)($28)
+       jalr    $25
+       addiu   $4, $28, %tlsgd(x)
+EOF
+if { ac_try='${CC-cc} -c $CFLAGS conftest.s 1>&5'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  libc_cv_mips_tls=yes
+else
+  libc_cv_mips_tls=no
+fi
+rm -f conftest*
+fi
+echo "$as_me:$LINENO: result: $libc_cv_mips_tls" >&5
+echo "${ECHO_T}$libc_cv_mips_tls" >&6
+if test $libc_cv_mips_tls = yes; then
+  cat >>confdefs.h <<\_ACEOF
+#define HAVE_TLS_SUPPORT 1
+_ACEOF
+
+fi
+fi
+
diff --git a/sysdeps/mips/elf/configure.in b/sysdeps/mips/elf/configure.in
new file mode 100644 (file)
index 0000000..ecb9108
--- /dev/null
@@ -0,0 +1,35 @@
+GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory.
+# Local configure fragment for sysdeps/mips/elf.
+
+if test "$usetls" != no; then
+# Check for support of thread-local storage handling in assembler and
+# linker.
+AC_CACHE_CHECK(for MIPS TLS support, libc_cv_mips_tls, [dnl
+cat > conftest.s <<\EOF
+       .section ".tdata", "awT", %progbits
+       .globl foo
+foo:   .long   1
+       .section ".tbss", "awT", %nobits
+       .globl bar
+bar:   .skip   4
+       .text
+
+       lw      $25, %call16(__tls_get_addr)($28)
+       jalr    $25
+       addiu   $4, $28, %tlsgd(x) 
+EOF
+dnl
+if AC_TRY_COMMAND(${CC-cc} -c $CFLAGS conftest.s 1>&AS_MESSAGE_LOG_FD); then
+  libc_cv_mips_tls=yes
+else
+  libc_cv_mips_tls=no
+fi
+rm -f conftest*])
+if test $libc_cv_mips_tls = yes; then
+  AC_DEFINE(HAVE_TLS_SUPPORT)
+fi
+fi
+
+dnl No MIPS GCC supports accessing static and hidden symbols in an
+dnl position independent way.
+dnl AC_DEFINE(PI_STATIC_AND_HIDDEN)
diff --git a/sysdeps/mips/libc-tls.c b/sysdeps/mips/libc-tls.c
new file mode 100644 (file)
index 0000000..157ba33
--- /dev/null
@@ -0,0 +1,37 @@
+/* Thread-local storage handling in the ELF dynamic linker.  MIPS version.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdeps/generic/libc-tls.c>
+#include <dl-tls.h>
+
+#if USE_TLS
+
+/* On MIPS, linker optimizations are not required, so __tls_get_addr
+   can be called even in statically linked binaries.  In this case module
+   must be always 1 and PT_TLS segment exist in the binary, otherwise it
+   would not link.  */
+
+void *
+__tls_get_addr (tls_index *ti)
+{
+  dtv_t *dtv = THREAD_DTV ();
+  return (char *) dtv[1].pointer.val + GET_ADDR_OFFSET;
+}
+
+#endif
index b04c36b..b590802 100644 (file)
@@ -1,4 +1,5 @@
-/* Copyright (C) 1997, 1998, 2002, 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998, 2002, 2003, 2004, 2005
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ralf Baechle <ralf@gnu.org>.
 
@@ -470,4 +471,20 @@ symbol             =       value
 # define MTC0  dmtc0
 #endif
 
+/* The MIPS archtectures do not have a uniform memory model.  Particular
+   platforms may provide additional guarantees - for instance, the R4000
+   LL and SC instructions implicitly perform a SYNC, and the 4K promises
+   strong ordering.
+
+   However, in the absence of those guarantees, we must assume weak ordering
+   and SYNC explicitly where necessary.
+
+   Some obsolete MIPS processors may not support the SYNC instruction.  This
+   applies to "true" MIPS I processors; most of the processors which compile
+   using MIPS I implement parts of MIPS II.  */
+
+#ifndef MIPS_SYNC
+# define MIPS_SYNC     sync
+#endif
+
 #endif /* sys/asm.h */
diff --git a/sysdeps/mips/tls-macros.h b/sysdeps/mips/tls-macros.h
new file mode 100644 (file)
index 0000000..2d0516b
--- /dev/null
@@ -0,0 +1,88 @@
+/* Macros to support TLS testing in times of missing compiler support.  */
+
+#if _MIPS_SIM != _ABI64
+
+/* These versions are for o32 and n32.  */
+
+# define TLS_GD(x)                                     \
+  ({ void *__result;                                   \
+     extern void *__tls_get_addr (void *);             \
+     asm ("addiu %0, $28, %%tlsgd(" #x ")"             \
+         : "=r" (__result));                           \
+     (int *)__tls_get_addr (__result); })
+#else
+# define TLS_GD(x)                                     \
+  ({ void *__result;                                   \
+     extern void *__tls_get_addr (void *);             \
+     asm ("daddiu %0, $28, %%tlsgd(" #x ")"            \
+         : "=r" (__result));                           \
+     (int *)__tls_get_addr (__result); })
+#endif
+
+#if _MIPS_SIM != _ABI64
+# define TLS_LD(x)                                     \
+  ({ void *__result;                                   \
+     extern void *__tls_get_addr (void *);             \
+     asm ("addiu %0, $28, %%tlsldm(" #x ")"            \
+         : "=r" (__result));                           \
+     __result = __tls_get_addr (__result);             \
+     asm ("lui $3,%%dtprel_hi(" #x ")\n\t"             \
+         "addiu $3,$3,%%dtprel_lo(" #x ")\n\t"         \
+         "addu %0,%0,$3"                               \
+         : "+r" (__result) : : "$3");                  \
+     __result; })
+# define TLS_IE(x)                                     \
+  ({ void *__result;                                   \
+     asm (".set push\n\t.set mips32r2\n\t"             \
+         "rdhwr\t%0,$29\n\t.set pop"                   \
+         : "=v" (__result));                           \
+     asm ("lw $3,%%gottprel(" #x ")($28)\n\t"          \
+         "addu %0,%0,$3"                               \
+         : "+r" (__result) : : "$3");                  \
+     __result; })
+# define TLS_LE(x)                                     \
+  ({ void *__result;                                   \
+     asm (".set push\n\t.set mips32r2\n\t"             \
+         "rdhwr\t%0,$29\n\t.set pop"                   \
+         : "=v" (__result));                           \
+     asm ("lui $3,%%tprel_hi(" #x ")\n\t"              \
+         "addiu $3,$3,%%tprel_lo(" #x ")\n\t"          \
+         "addu %0,%0,$3"                               \
+         : "+r" (__result) : : "$3");                  \
+     __result; })
+
+#else
+
+/* These versions are for n64.  */
+
+# define TLS_LD(x)                                     \
+  ({ void *__result;                                   \
+     extern void *__tls_get_addr (void *);             \
+     asm ("daddiu %0, $28, %%tlsldm(" #x ")"           \
+         : "=r" (__result));                           \
+     __result = __tls_get_addr (__result);             \
+     asm ("lui $3,%%dtprel_hi(" #x ")\n\t"             \
+         "daddiu $3,$3,%%dtprel_lo(" #x ")\n\t"        \
+         "daddu %0,%0,$3"                              \
+         : "+r" (__result) : : "$3");                  \
+     __result; })
+# define TLS_IE(x)                                     \
+  ({ void *__result;                                   \
+     asm (".set push\n\t.set mips32r2\n\t"             \
+         "rdhwr\t%0,$29\n\t.set pop"                   \
+         : "=v" (__result));                           \
+     asm ("ld $3,%%gottprel(" #x ")($28)\n\t"          \
+         "daddu %0,%0,$3"                              \
+         : "+r" (__result) : : "$3");                  \
+     __result; })
+# define TLS_LE(x)                                     \
+  ({ void *__result;                                   \
+     asm (".set push\n\t.set mips32r2\n\t"             \
+         "rdhwr\t%0,$29\n\t.set pop"                   \
+         : "=v" (__result));                           \
+     asm ("lui $3,%%tprel_hi(" #x ")\n\t"              \
+         "daddiu $3,$3,%%tprel_lo(" #x ")\n\t"         \
+         "daddu %0,%0,$3"                              \
+         : "+r" (__result) : : "$3");                  \
+     __result; })
+#endif
index 54eba41..787e365 100644 (file)
@@ -1,5 +1,5 @@
 /* siginfo_t, sigevent and constants.  Linux/MIPS version.
-   Copyright (C) 1997, 1998, 2000, 2001, 2002, 2003, 2004
+   Copyright (C) 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005
        Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
@@ -300,10 +300,11 @@ enum
 # define SIGEV_SIGNAL  SIGEV_SIGNAL
   SIGEV_NONE,                  /* Other notification: meaningless.  */
 # define SIGEV_NONE    SIGEV_NONE
-  SIGEV_CALLBACK,              /* Deliver via thread creation.  */
-# define SIGEV_CALLBACK        SIGEV_CALLBACK
-  SIGEV_THREAD                 /* Deliver via thread creation.  */
+  SIGEV_THREAD,                        /* Deliver via thread creation.  */
 # define SIGEV_THREAD  SIGEV_THREAD
+
+  SIGEV_THREAD_ID = 4          /* Send signal to specific thread.  */
+#define SIGEV_THREAD_ID        SIGEV_THREAD_ID
 };
 
 #endif /* have _SIGNAL_H.  */
index 043f592..8b8e007 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997, 2000, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 2000, 2003, 2005 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ralf Baechle <ralf@linux-mips.org>, 1996.
 
 #include <sysdep.h>
 #define _ERRNO_H       1
 #include <bits/errno.h>
+#ifdef RESET_PID
+#include <tls.h>
+#endif
+
+#define CLONE_VM      0x00000100
+#define CLONE_THREAD  0x00010000
 
-/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg) */
+/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
+            void *parent_tidptr, void *tls, void *child_tidptr) */
 
        .text
-LOCALSZ= 1
+#if _MIPS_SIM == _ABIO32
+# define EXTRA_LOCALS 1
+#else
+# define EXTRA_LOCALS 0
+#endif
+LOCALSZ= 4
 FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK
 GPOFF= FRAMESZ-(1*SZREG)
 NESTED(__clone,4*SZREG,sp)
@@ -56,10 +68,26 @@ NESTED(__clone,4*SZREG,sp)
        PTR_SUBU        a1,32           /* Reserve argument save space.  */
        PTR_S           a0,0(a1)        /* Save function pointer.  */
        PTR_S           a3,PTRSIZE(a1)  /* Save argument pointer.  */
+#ifdef RESET_PID
+       LONG_S          a2,(PTRSIZE*2)(a1)      /* Save clone flags.  */
+#endif
 
+       move            a0,a2
+
+       /* Shuffle in the last three arguments - arguments 5, 6, and 7 to
+          this function, but arguments 3, 4, and 5 to the syscall.  */
+#if _MIPS_SIM == _ABIO32
+       PTR_L           a2,(FRAMESZ+PTRSIZE+PTRSIZE+16)(sp)
+       PTR_S           a2,16(sp)
+       PTR_L           a2,(FRAMESZ+16)(sp)
+       PTR_L           a3,(FRAMESZ+PTRSIZE+16)(sp)
+#else
+       move            a2,a4
+       move            a3,a5
+       move            a4,a6
+#endif
 
        /* Do the system call */
-       move            a0,a2
        li              v0,__NR_clone
        syscall
 
@@ -94,6 +122,15 @@ L(thread_start):
        /* cp is already loaded.  */
        SAVE_GP (GPOFF)
        /* The stackframe has been created on entry of clone().  */
+
+#ifdef RESET_PID
+       /* Check and see if we need to reset the PID.  */
+       LONG_L          a0,(PTRSIZE*2)(sp)
+       and             a1,a0,CLONE_THREAD
+       beqz            a1,L(restore_pid)
+L(donepid):
+#endif
+
        /* Restore the arg for user's function.  */
        PTR_L           t9,0(sp)        /* Function pointer.  */
        PTR_L           a0,PTRSIZE(sp)  /* Argument pointer.  */
@@ -109,6 +146,21 @@ L(thread_start):
 #else
        jal             _exit
 #endif
+
+#ifdef RESET_PID
+L(restore_pid):
+       and             a1,a0,CLONE_VM
+       li              v0,-1
+       bnez            a1,L(gotpid)
+       li              v0,__NR_getpid
+       syscall
+L(gotpid):
+       READ_THREAD_POINTER(v1)
+       INT_S           v0,PID_OFFSET(v1)
+       INT_S           v0,TID_OFFSET(v1)
+       b               L(donepid)
+#endif
+
        END(__thread_start)
 
 weak_alias(__clone, clone)
index 682ec3d..3da2412 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000, 2002, 2003, 2004 Free Software Foundation, Inc.
+/* 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
 #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;                                             \
-       }                                                                \
+     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_ERRNO(val, err)     (val)
 
 #undef INTERNAL_SYSCALL
-#define INTERNAL_SYSCALL(name, err, nr, args...) internal_syscall##nr(name, err, args)
+#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)
 
-#define internal_syscall0(name, err, dummy...)                                 \
-({                                                                     \
+#undef INTERNAL_SYSCALL_NCS
+#define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \
+       internal_syscall##nr (= number, , "r" (__v0), err, args)
+
+#define internal_syscall0(ncs_init, cs_init, input, err, dummy...)     \
+({                                                                     \
        long _sys_result;                                               \
                                                                        \
        {                                                               \
-       register long __v0 asm("$2");                                   \
-       register long __a3 asm("$7");                                   \
-       __asm__ volatile (                                              \
-       ".set\tnoreorder\n\t"                                           \
-       "li\t$2, %2\t\t\t# " #name "\n\t"                               \
-       "syscall\n\t"                                                   \
-       ".set reorder"                                                  \
-       : "=r" (__v0), "=r" (__a3)                                      \
-       : "i" (SYS_ify(name))                                           \
-       : __SYSCALL_CLOBBERS);                                          \
+       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;                                                    \
 })
 
-#define internal_syscall1(name, err, arg1)                             \
-({                                                                     \
+#define internal_syscall1(ncs_init, cs_init, input, err, arg1)         \
+({                                                                     \
        long _sys_result;                                               \
                                                                        \
        {                                                               \
-       register long __v0 asm("$2");                                   \
-       register long __a0 asm("$4") = (long) arg1;                     \
-       register long __a3 asm("$7");                                   \
-       __asm__ volatile (                                              \
-       ".set\tnoreorder\n\t"                                           \
-       "li\t$2, %3\t\t\t# " #name "\n\t"                               \
-       "syscall\n\t"                                                   \
-       ".set reorder"                                                  \
-       : "=r" (__v0), "=r" (__a3)                                      \
-       : "r" (__a0), "i" (SYS_ify(name))                               \
-       : __SYSCALL_CLOBBERS);                                          \
+       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;                                                    \
 })
 
-#define internal_syscall2(name, err, arg1, arg2)                       \
-({                                                                     \
+#define internal_syscall2(ncs_init, cs_init, input, err, arg1, arg2)   \
+({                                                                     \
        long _sys_result;                                               \
                                                                        \
        {                                                               \
-       register long __v0 asm("$2");                                   \
-       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"                                           \
-       "li\t$2, %4\t\t\t# " #name "\n\t"                               \
-       "syscall\n\t"                                                   \
-       ".set\treorder"                                                 \
-       : "=r" (__v0), "=r" (__a3)                                      \
-       : "r" (__a0), "r" (__a1), "i" (SYS_ify(name))                   \
-       : __SYSCALL_CLOBBERS);                                          \
+       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;                                                    \
 })
 
-#define internal_syscall3(name, err, arg1, arg2, arg3)                         \
-({                                                                     \
+#define internal_syscall3(ncs_init, cs_init, input, err, arg1, arg2, arg3)\
+({                                                                     \
        long _sys_result;                                               \
                                                                        \
        {                                                               \
-       register long __v0 asm("$2");                                   \
-       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"                                           \
-       "li\t$2, %5\t\t\t# " #name "\n\t"                               \
-       "syscall\n\t"                                                   \
-       ".set\treorder"                                                 \
-       : "=r" (__v0), "=r" (__a3)                                      \
-       : "r" (__a0), "r" (__a1), "r" (__a2), "i" (SYS_ify(name))       \
-       : __SYSCALL_CLOBBERS);                                          \
+       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;                                                    \
 })
 
-#define internal_syscall4(name, err, arg1, arg2, arg3, arg4)           \
-({                                                                     \
+#define internal_syscall4(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4)\
+({                                                                     \
        long _sys_result;                                               \
                                                                        \
        {                                                               \
-       register long __v0 asm("$2");                                   \
-       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"                                           \
-       "li\t$2, %5\t\t\t# " #name "\n\t"                               \
-       "syscall\n\t"                                                   \
-       ".set\treorder"                                                 \
-       : "=r" (__v0), "+r" (__a3)                                      \
-       : "r" (__a0), "r" (__a1), "r" (__a2), "i" (SYS_ify(name))       \
-       : __SYSCALL_CLOBBERS);                                          \
+       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;                                                    \
 })
 
-#define internal_syscall5(name, err, arg1, arg2, arg3, arg4, arg5)     \
-({                                                                     \
+/* 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)
+
+#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");                                   \
-       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"                                           \
-       "li\t$2, %5\t\t\t# " #name "\n\t"                               \
-       "syscall\n\t"                                                   \
-       "addiu\t$29, 32\n\t"                                            \
-       ".set\treorder"                                                 \
-       : "=r" (__v0), "+r" (__a3)                                      \
-       : "r" (__a0), "r" (__a1), "r" (__a2), "i" (SYS_ify(name)),      \
-         "r" ((long)arg5)                                              \
-       : __SYSCALL_CLOBBERS);                                          \
+       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;                                                    \
 })
 
-#define internal_syscall6(name, err, arg1, arg2, arg3, arg4, arg5, arg6)\
-({                                                                     \
+#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");                                   \
-       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"                                           \
-       "li\t$2, %5\t\t\t# " #name "\n\t"                               \
-       "syscall\n\t"                                                   \
-       "addiu\t$29, 32\n\t"                                            \
-       ".set\treorder"                                                 \
-       : "=r" (__v0), "+r" (__a3)                                      \
-       : "r" (__a0), "r" (__a1), "r" (__a2), "i" (SYS_ify(name)),      \
+       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);                                          \
+       : __SYSCALL_CLOBBERS);                                          \
        err = __a3;                                                     \
        _sys_result = __v0;                                             \
        }                                                               \
        _sys_result;                                                    \
 })
 
-#define internal_syscall7(name, err, arg1, arg2, arg3, arg4, arg5, arg6, arg7)\
-({                                                                     \
+#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");                                   \
-       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"                                           \
-       "li\t$2, %5\t\t\t# " #name "\n\t"                               \
-       "syscall\n\t"                                                   \
-       "addiu\t$29, 32\n\t"                                            \
-       ".set\treorder"                                                 \
-       : "=r" (__v0), "+r" (__a3)                                      \
-       : "r" (__a0), "r" (__a1), "r" (__a2), "i" (SYS_ify(name)),      \
+       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);                                          \
+       : __SYSCALL_CLOBBERS);                                          \
        err = __a3;                                                     \
        _sys_result = __v0;                                             \
        }                                                               \
diff --git a/sysdeps/unix/sysv/linux/mips/vfork.S b/sysdeps/unix/sysv/linux/mips/vfork.S
new file mode 100644 (file)
index 0000000..1383ddc
--- /dev/null
@@ -0,0 +1,98 @@
+/* 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.  */
+
+/* vfork() is just a special case of clone().  */
+
+#include <sys/asm.h>
+#include <sysdep.h>
+#include <asm/unistd.h>
+#include <sgidefs.h>
+
+#ifndef SAVE_PID
+#define SAVE_PID
+#endif
+
+#ifndef RESTORE_PID
+#define RESTORE_PID
+#endif
+
+
+/* int vfork() */
+
+       .text
+LOCALSZ= 1
+FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK
+GPOFF= FRAMESZ-(1*SZREG)
+NESTED(__vfork,FRAMESZ,sp)
+#ifdef __PIC__
+       SETUP_GP
+#endif
+       PTR_SUBU sp, FRAMESZ
+       SETUP_GP64 (a5, __vfork)
+#ifdef __PIC__
+       SAVE_GP (GPOFF)
+#endif
+#ifdef PROF
+# if (_MIPS_SIM != _ABIO32)
+       PTR_S           a5, GPOFF(sp)
+# endif
+       .set            noat
+       move            $1, ra
+# if (_MIPS_SIM == _ABIO32)
+       subu            sp,sp,8
+# endif
+       jal             _mcount
+       .set            at
+# if (_MIPS_SIM != _ABIO32)
+       PTR_L           a5, GPOFF(sp)
+# endif
+#endif
+
+       PTR_ADDU        sp, FRAMESZ
+
+       SAVE_PID
+
+       li              a0, 0x4112      /* CLONE_VM | CLONE_VFORK | SIGCHLD */
+       move            a1, sp
+
+       /* Do the system call */
+       li              v0,__NR_clone
+       syscall
+
+       RESTORE_PID
+
+       bnez            a3,L(error)
+
+       /* Successful return from the parent or child.  */
+       RESTORE_GP64
+       ret
+
+       /* Something bad happened -- no child created.  */
+L(error):
+#ifdef __PIC__
+       PTR_LA          t9, __syscall_error
+       RESTORE_GP64
+       jr              t9
+#else
+       RESTORE_GP64
+       j               __syscall_error
+#endif
+       END(__vfork)
+
+libc_hidden_def(__vfork)
+weak_alias(__vfork, vfork)