summaryrefslogtreecommitdiff
path: root/nptl/sysdeps/unix/sysv/linux/mips
diff options
context:
space:
mode:
Diffstat (limited to 'nptl/sysdeps/unix/sysv/linux/mips')
-rw-r--r--nptl/sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h193
-rw-r--r--nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h40
-rw-r--r--nptl/sysdeps/unix/sysv/linux/mips/clone.S2
-rw-r--r--nptl/sysdeps/unix/sysv/linux/mips/createthread.c24
-rw-r--r--nptl/sysdeps/unix/sysv/linux/mips/fork.c1
-rw-r--r--nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h216
-rw-r--r--nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S37
-rw-r--r--nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c94
-rw-r--r--nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h170
-rw-r--r--nptl/sysdeps/unix/sysv/linux/mips/vfork.S42
10 files changed, 819 insertions, 0 deletions
diff --git a/nptl/sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h
new file mode 100644
index 0000000000..e14a487508
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/mips/bits/pthreadtypes.h
@@ -0,0 +1,193 @@
+/* Machine-specific pthread type layouts. MIPS version.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _BITS_PTHREADTYPES_H
+#define _BITS_PTHREADTYPES_H 1
+
+#if _MIPS_SIM == _ABI64
+# define __SIZEOF_PTHREAD_ATTR_T 56
+# define __SIZEOF_PTHREAD_MUTEX_T 40
+# define __SIZEOF_PTHREAD_MUTEXATTR_T 4
+# define __SIZEOF_PTHREAD_COND_T 48
+# define __SIZEOF_PTHREAD_CONDATTR_T 4
+# define __SIZEOF_PTHREAD_RWLOCK_T 56
+# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
+# define __SIZEOF_PTHREAD_BARRIER_T 32
+# define __SIZEOF_PTHREAD_BARRIERATTR_T 4
+#else
+# define __SIZEOF_PTHREAD_ATTR_T 36
+# define __SIZEOF_PTHREAD_MUTEX_T 24
+# define __SIZEOF_PTHREAD_MUTEXATTR_T 4
+# define __SIZEOF_PTHREAD_COND_T 48
+# define __SIZEOF_PTHREAD_CONDATTR_T 4
+# define __SIZEOF_PTHREAD_RWLOCK_T 32
+# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
+# define __SIZEOF_PTHREAD_BARRIER_T 20
+# define __SIZEOF_PTHREAD_BARRIERATTR_T 4
+#endif
+
+
+/* Thread identifiers. The structure of the attribute type is
+ deliberately not exposed. */
+typedef unsigned long int pthread_t;
+
+
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_ATTR_T];
+ long int __align;
+} pthread_attr_t;
+
+
+/* Data structures for mutex handling. The structure of the attribute
+ type is deliberately not exposed. */
+typedef union
+{
+ struct
+ {
+ int __lock;
+ unsigned int __count;
+ int __owner;
+#if _MIPS_SIM == _ABI64
+ unsigned int __nusers;
+#endif
+ /* KIND must stay at this position in the structure to maintain
+ binary compatibility. */
+ int __kind;
+#if _MIPS_SIM != _ABI64
+ unsigned int __nusers;
+#endif
+ int __spins;
+ } __data;
+ char __size[__SIZEOF_PTHREAD_MUTEX_T];
+ long int __align;
+} pthread_mutex_t;
+
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_MUTEXATTR_T];
+ int __align;
+} pthread_mutexattr_t;
+
+
+/* Data structure for conditional variable handling. The structure of
+ the attribute type is deliberately not exposed. */
+typedef union
+{
+ struct
+ {
+ int __lock;
+ unsigned int __futex;
+ __extension__ unsigned long long int __total_seq;
+ __extension__ unsigned long long int __wakeup_seq;
+ __extension__ unsigned long long int __woken_seq;
+ void *__mutex;
+ unsigned int __nwaiters;
+ unsigned int __broadcast_seq;
+ } __data;
+ char __size[__SIZEOF_PTHREAD_COND_T];
+ __extension__ long long int __align;
+} pthread_cond_t;
+
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_CONDATTR_T];
+ int __align;
+} pthread_condattr_t;
+
+
+/* Keys for thread-specific data */
+typedef unsigned int pthread_key_t;
+
+
+/* Once-only execution */
+typedef int pthread_once_t;
+
+
+#if defined __USE_UNIX98 || defined __USE_XOPEN2K
+/* Data structure for read-write lock variable handling. The
+ structure of the attribute type is deliberately not exposed. */
+typedef union
+{
+# if _MIPS_SIM == _ABI64
+ struct
+ {
+ int __lock;
+ unsigned int __nr_readers;
+ unsigned int __readers_wakeup;
+ unsigned int __writer_wakeup;
+ unsigned int __nr_readers_queued;
+ unsigned int __nr_writers_queued;
+ int __writer;
+ int __pad1;
+ unsigned long int __pad2;
+ unsigned long int __pad3;
+ /* FLAGS must stay at this position in the structure to maintain
+ binary compatibility. */
+ unsigned int __flags;
+ } __data;
+# else
+ struct
+ {
+ int __lock;
+ unsigned int __nr_readers;
+ unsigned int __readers_wakeup;
+ unsigned int __writer_wakeup;
+ unsigned int __nr_readers_queued;
+ unsigned int __nr_writers_queued;
+ /* FLAGS must stay at this position in the structure to maintain
+ binary compatibility. */
+ unsigned int __flags;
+ int __writer;
+ } __data;
+# endif
+ char __size[__SIZEOF_PTHREAD_RWLOCK_T];
+ long int __align;
+} pthread_rwlock_t;
+
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T];
+ long int __align;
+} pthread_rwlockattr_t;
+#endif
+
+
+#ifdef __USE_XOPEN2K
+/* POSIX spinlock data type. */
+typedef volatile int pthread_spinlock_t;
+
+
+/* POSIX barriers data type. The structure of the type is
+ deliberately not exposed. */
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_BARRIER_T];
+ long int __align;
+} pthread_barrier_t;
+
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_BARRIERATTR_T];
+ int __align;
+} pthread_barrierattr_t;
+#endif
+
+
+#endif /* bits/pthreadtypes.h */
diff --git a/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h b/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h
new file mode 100644
index 0000000000..c4440f9e9e
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/mips/bits/semaphore.h
@@ -0,0 +1,40 @@
+/* Copyright (C) 2002, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _SEMAPHORE_H
+# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead."
+#endif
+
+#if _MIPS_SIM == _ABI64
+# define __SIZEOF_SEM_T 32
+#else
+# define __SIZEOF_SEM_T 16
+#endif
+
+/* Value returned if `sem_open' failed. */
+#define SEM_FAILED ((sem_t *) 0)
+
+/* Maximum value the semaphore can have. */
+#define SEM_VALUE_MAX (2147483647)
+
+
+typedef union
+{
+ char __size[__SIZEOF_SEM_T];
+ long int __align;
+} sem_t;
diff --git a/nptl/sysdeps/unix/sysv/linux/mips/clone.S b/nptl/sysdeps/unix/sysv/linux/mips/clone.S
new file mode 100644
index 0000000000..80c265bf6c
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/mips/clone.S
@@ -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
index 0000000000..5b2234f470
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/mips/createthread.c
@@ -0,0 +1,24 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/* Value passed to 'clone' for initialization of the thread register. */
+#define TLS_VALUE ((void *) (pd) \
+ + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE)
+
+/* Get the real implementation. */
+#include <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
index 0000000000..06b7e1c69f
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/mips/fork.c
@@ -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
index 0000000000..7edb28794f
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/mips/lowlevellock.h
@@ -0,0 +1,216 @@
+/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _LOWLEVELLOCK_H
+#define _LOWLEVELLOCK_H 1
+
+#include <time.h>
+#include <sys/param.h>
+#include <bits/pthreadtypes.h>
+#include <atomic.h>
+#include <sysdep.h>
+
+
+#define FUTEX_WAIT 0
+#define FUTEX_WAKE 1
+#define FUTEX_REQUEUE 3
+#define FUTEX_CMP_REQUEUE 4
+
+/* Initializer for compatibility lock. */
+#define LLL_MUTEX_LOCK_INITIALIZER (0)
+
+#define lll_futex_wait(futexp, val) \
+ ({ \
+ INTERNAL_SYSCALL_DECL (__err); \
+ long int __ret; \
+ __ret = INTERNAL_SYSCALL (futex, __err, 4, \
+ (futexp), FUTEX_WAIT, (val), 0); \
+ INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret; \
+ })
+
+#define lll_futex_timed_wait(futexp, val, timespec) \
+ ({ \
+ INTERNAL_SYSCALL_DECL (__err); \
+ long int __ret; \
+ __ret = INTERNAL_SYSCALL (futex, __err, 4, \
+ (futexp), FUTEX_WAIT, (val), (timespec)); \
+ INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret; \
+ })
+
+#define lll_futex_wake(futexp, nr) \
+ ({ \
+ INTERNAL_SYSCALL_DECL (__err); \
+ long int __ret; \
+ __ret = INTERNAL_SYSCALL (futex, __err, 4, \
+ (futexp), FUTEX_WAKE, (nr), 0); \
+ INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret; \
+ })
+
+/* Returns non-zero if error happened, zero if success. */
+#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val) \
+ ({ \
+ INTERNAL_SYSCALL_DECL (__err); \
+ long int __ret; \
+ __ret = INTERNAL_SYSCALL (futex, __err, 6, \
+ (futexp), FUTEX_CMP_REQUEUE, (nr_wake), \
+ (nr_move), (mutex), (val)); \
+ INTERNAL_SYSCALL_ERROR_P (__ret, __err); \
+ })
+
+
+static inline int __attribute__((always_inline))
+__lll_mutex_trylock(int *futex)
+{
+ return atomic_compare_and_exchange_val_acq (futex, 1, 0) != 0;
+}
+#define lll_mutex_trylock(lock) __lll_mutex_trylock (&(lock))
+
+
+static inline int __attribute__((always_inline))
+__lll_mutex_cond_trylock(int *futex)
+{
+ return atomic_compare_and_exchange_val_acq (futex, 2, 0) != 0;
+}
+#define lll_mutex_cond_trylock(lock) __lll_mutex_cond_trylock (&(lock))
+
+
+extern void __lll_lock_wait (int *futex) attribute_hidden;
+
+static inline void __attribute__((always_inline))
+__lll_mutex_lock(int *futex)
+{
+ if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0)
+ __lll_lock_wait (futex);
+}
+#define lll_mutex_lock(futex) __lll_mutex_lock (&(futex))
+
+
+static inline void __attribute__ ((always_inline))
+__lll_mutex_cond_lock (int *futex)
+{
+ if (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0)
+ __lll_lock_wait (futex);
+}
+#define lll_mutex_cond_lock(futex) __lll_mutex_cond_lock (&(futex))
+
+
+extern int __lll_timedlock_wait (int *futex, const struct timespec *)
+ attribute_hidden;
+
+static inline int __attribute__ ((always_inline))
+__lll_mutex_timedlock (int *futex, const struct timespec *abstime)
+{
+ int result = 0;
+ if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0)
+ result = __lll_timedlock_wait (futex, abstime);
+ return result;
+}
+#define lll_mutex_timedlock(futex, abstime) \
+ __lll_mutex_timedlock (&(futex), abstime)
+
+
+static inline void __attribute__ ((always_inline))
+__lll_mutex_unlock (int *futex)
+{
+ int val = atomic_exchange_rel (futex, 0);
+ if (__builtin_expect (val > 1, 0))
+ lll_futex_wake (futex, 1);
+}
+#define lll_mutex_unlock(futex) __lll_mutex_unlock(&(futex))
+
+
+static inline void __attribute__ ((always_inline))
+__lll_mutex_unlock_force (int *futex)
+{
+ (void) atomic_exchange_rel (futex, 0);
+ lll_futex_wake (futex, 1);
+}
+#define lll_mutex_unlock_force(futex) __lll_mutex_unlock_force(&(futex))
+
+
+#define lll_mutex_islocked(futex) \
+ (futex != 0)
+
+
+/* Our internal lock implementation is identical to the binary-compatible
+ mutex implementation. */
+
+/* Type for lock object. */
+typedef int lll_lock_t;
+
+/* Initializers for lock. */
+#define LLL_LOCK_INITIALIZER (0)
+#define LLL_LOCK_INITIALIZER_LOCKED (1)
+
+extern int lll_unlock_wake_cb (int *__futex) attribute_hidden;
+
+/* The states of a lock are:
+ 0 - untaken
+ 1 - taken by one user
+ >1 - taken by more users */
+
+#define lll_trylock(lock) lll_mutex_trylock (lock)
+#define lll_lock(lock) lll_mutex_lock (lock)
+#define lll_unlock(lock) lll_mutex_unlock (lock)
+#define lll_islocked(lock) lll_mutex_islocked (lock)
+
+/* The kernel notifies a process which uses CLONE_CLEARTID via futex
+ wakeup when the clone terminates. The memory location contains the
+ thread ID while the clone is running and is reset to zero
+ afterwards. */
+#define lll_wait_tid(tid) \
+ do { \
+ __typeof (tid) __tid; \
+ while ((__tid = (tid)) != 0) \
+ lll_futex_wait (&(tid), __tid); \
+ } while (0)
+
+extern int __lll_timedwait_tid (int *, const struct timespec *)
+ attribute_hidden;
+
+#define lll_timedwait_tid(tid, abstime) \
+ ({ \
+ int __res = 0; \
+ if ((tid) != 0) \
+ __res = __lll_timedwait_tid (&(tid), (abstime)); \
+ __res; \
+ })
+
+
+/* Conditional variable handling. */
+
+extern void __lll_cond_wait (pthread_cond_t *cond)
+ attribute_hidden;
+extern int __lll_cond_timedwait (pthread_cond_t *cond,
+ const struct timespec *abstime)
+ attribute_hidden;
+extern void __lll_cond_wake (pthread_cond_t *cond)
+ attribute_hidden;
+extern void __lll_cond_broadcast (pthread_cond_t *cond)
+ attribute_hidden;
+
+#define lll_cond_wait(cond) \
+ __lll_cond_wait (cond)
+#define lll_cond_timedwait(cond, abstime) \
+ __lll_cond_timedwait (cond, abstime)
+#define lll_cond_wake(cond) \
+ __lll_cond_wake (cond)
+#define lll_cond_broadcast(cond) \
+ __lll_cond_broadcast (cond)
+
+#endif /* lowlevellock.h */
diff --git a/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S b/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S
new file mode 100644
index 0000000000..fe2b81bc1f
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/mips/pt-vfork.S
@@ -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
index 0000000000..649b752f54
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/mips/pthread_once.c
@@ -0,0 +1,94 @@
+/* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+unsigned long int __fork_generation attribute_hidden;
+
+
+static void
+clear_once_control (void *arg)
+{
+ pthread_once_t *once_control = (pthread_once_t *) arg;
+
+ *once_control = 0;
+ lll_futex_wake (once_control, INT_MAX);
+}
+
+
+int
+__pthread_once (once_control, init_routine)
+ pthread_once_t *once_control;
+ void (*init_routine) (void);
+{
+ while (1)
+ {
+ int oldval, val, newval;
+
+ val = *once_control;
+ do
+ {
+ /* Check if the initialized has already been done. */
+ if ((val & 2) != 0)
+ return 0;
+
+ oldval = val;
+ newval = (oldval & 3) | __fork_generation | 1;
+ val = atomic_compare_and_exchange_val_acq (once_control, newval,
+ oldval);
+ }
+ while (__builtin_expect (val != oldval, 0));
+
+ /* Check if another thread already runs the initializer. */
+ if ((oldval & 1) != 0)
+ {
+ /* Check whether the initializer execution was interrupted
+ by a fork. */
+ if (((oldval ^ newval) & -4) == 0)
+ {
+ /* Same generation, some other thread was faster. Wait. */
+ lll_futex_wait (once_control, newval);
+ continue;
+ }
+ }
+
+ /* This thread is the first here. Do the initialization.
+ Register a cleanup handler so that in case the thread gets
+ interrupted the initialization can be restarted. */
+ pthread_cleanup_push (clear_once_control, once_control);
+
+ init_routine ();
+
+ pthread_cleanup_pop (0);
+
+
+ /* Add one to *once_control. */
+ atomic_increment (once_control);
+
+ /* Wake up all other threads. */
+ lll_futex_wake (once_control, INT_MAX);
+ break;
+ }
+
+ return 0;
+}
+weak_alias (__pthread_once, pthread_once)
+strong_alias (__pthread_once, __pthread_once_internal)
diff --git a/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h b/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h
new file mode 100644
index 0000000000..02508e2155
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/mips/sysdep-cancel.h
@@ -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
index 0000000000..874a2e2bf4
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/mips/vfork.S
@@ -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>