MIPS NPTL support
authorAndreas Jaeger <aj@suse.de>
Mon, 28 Mar 2005 09:21:52 +0000 (09:21 +0000)
committerAndreas Jaeger <aj@suse.de>
Mon, 28 Mar 2005 09:21:52 +0000 (09:21 +0000)
sysdeps/unix/sysv/linux/mips/nptl/bits/semaphore.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/mips/nptl/clone.S [new file with mode: 0644]
sysdeps/unix/sysv/linux/mips/nptl/createthread.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/mips/nptl/fork.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/mips/nptl/lowlevellock.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/mips/nptl/pt-vfork.S [new file with mode: 0644]
sysdeps/unix/sysv/linux/mips/nptl/pthread_once.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/mips/nptl/sysdep-cancel.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/mips/nptl/vfork.S [new file with mode: 0644]

diff --git a/sysdeps/unix/sysv/linux/mips/nptl/bits/semaphore.h b/sysdeps/unix/sysv/linux/mips/nptl/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/sysdeps/unix/sysv/linux/mips/nptl/clone.S b/sysdeps/unix/sysv/linux/mips/nptl/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/sysdeps/unix/sysv/linux/mips/nptl/createthread.c b/sysdeps/unix/sysv/linux/mips/nptl/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/sysdeps/unix/sysv/linux/mips/nptl/fork.c b/sysdeps/unix/sysv/linux/mips/nptl/fork.c
new file mode 100644 (file)
index 0000000..06b7e1c
--- /dev/null
@@ -0,0 +1 @@
+#include "../i386/fork.c"
diff --git a/sysdeps/unix/sysv/linux/mips/nptl/lowlevellock.h b/sysdeps/unix/sysv/linux/mips/nptl/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/sysdeps/unix/sysv/linux/mips/nptl/pt-vfork.S b/sysdeps/unix/sysv/linux/mips/nptl/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/sysdeps/unix/sysv/linux/mips/nptl/pthread_once.c b/sysdeps/unix/sysv/linux/mips/nptl/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/sysdeps/unix/sysv/linux/mips/nptl/sysdep-cancel.h b/sysdeps/unix/sysv/linux/mips/nptl/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/sysdeps/unix/sysv/linux/mips/nptl/vfork.S b/sysdeps/unix/sysv/linux/mips/nptl/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>