2003-03-17 Roland McGrath <roland@redhat.com>
authorRoland McGrath <roland@gnu.org>
Mon, 17 Mar 2003 11:22:52 +0000 (11:22 +0000)
committerRoland McGrath <roland@gnu.org>
Mon, 17 Mar 2003 11:22:52 +0000 (11:22 +0000)
PowerPC port contributed by Paul Mackerras <paulus@samba.org>.
* sysdeps/pthread/pthread_spin_init.c: New file.
* sysdeps/pthread/pthread_spin_unlock.c: New file.
* sysdeps/powerpc/Makefile: New file.
* sysdeps/powerpc/pthread_spin_lock.c: New file.
* sysdeps/powerpc/pthread_spin_trylock.c: New file.
* sysdeps/powerpc/pthreaddef.h: New file.
* sysdeps/powerpc/tcb-offsets.sym: New file.
* sysdeps/powerpc/td_ta_map_lwp2thr.c: New file.
* sysdeps/powerpc/tls.h: New file.
* sysdeps/powerpc/bits/atomic.h: New file.
* sysdeps/unix/sysv/linux/libc-lowlevelmutex.c: New file.
* sysdeps/unix/sysv/linux/libc-lowlevellock.c: New file.
* sysdeps/unix/sysv/linux/lowlevellock.c: New file.
* sysdeps/unix/sysv/linux/sem_post.c: New file.
* sysdeps/unix/sysv/linux/sem_timedwait.c: New file.
* sysdeps/unix/sysv/linux/sem_trywait.c: New file.
* sysdeps/unix/sysv/linux/powerpc/Makefile: New file.
* sysdeps/unix/sysv/linux/powerpc/createthread.c: New file.
* sysdeps/unix/sysv/linux/powerpc/fork.c: New file.
* sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: New file.
* sysdeps/unix/sysv/linux/powerpc/pt-vfork.S: New file.
* sysdeps/unix/sysv/linux/powerpc/pthread_once.c: New file.
* sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: New file.
* sysdeps/unix/sysv/linux/powerpc/bits/semaphore.h: New file.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h: New file.
* sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h: New file.

26 files changed:
nptl/sysdeps/powerpc/Makefile [new file with mode: 0644]
nptl/sysdeps/powerpc/bits/atomic.h [new file with mode: 0644]
nptl/sysdeps/powerpc/pthread_spin_lock.c [new file with mode: 0644]
nptl/sysdeps/powerpc/pthread_spin_trylock.c [new file with mode: 0644]
nptl/sysdeps/powerpc/pthreaddef.h [new file with mode: 0644]
nptl/sysdeps/powerpc/tcb-offsets.sym [new file with mode: 0644]
nptl/sysdeps/powerpc/td_ta_map_lwp2thr.c [new file with mode: 0644]
nptl/sysdeps/powerpc/tls.h [new file with mode: 0644]
nptl/sysdeps/pthread/pthread_spin_init.c [new file with mode: 0644]
nptl/sysdeps/pthread/pthread_spin_unlock.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/libc-lowlevellock.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/libc-lowlevelmutex.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/lowlevellock.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/powerpc/Makefile [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/powerpc/bits/semaphore.h [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/powerpc/createthread.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/powerpc/fork.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/powerpc/pt-vfork.S [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/powerpc/pthread_once.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/sem_post.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/sem_timedwait.c [new file with mode: 0644]
nptl/sysdeps/unix/sysv/linux/sem_trywait.c [new file with mode: 0644]

diff --git a/nptl/sysdeps/powerpc/Makefile b/nptl/sysdeps/powerpc/Makefile
new file mode 100644 (file)
index 0000000..3af2456
--- /dev/null
@@ -0,0 +1,21 @@
+# Copyright (C) 2003 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
diff --git a/nptl/sysdeps/powerpc/bits/atomic.h b/nptl/sysdeps/powerpc/bits/atomic.h
new file mode 100644 (file)
index 0000000..af61563
--- /dev/null
@@ -0,0 +1,116 @@
+/* Atomic operations.  PowerPC version.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.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 <stdint.h>
+
+typedef int8_t atomic8_t;
+typedef uint8_t uatomic8_t;
+typedef int_fast8_t atomic_fast8_t;
+typedef uint_fast8_t uatomic_fast8_t;
+
+typedef int16_t atomic16_t;
+typedef uint16_t uatomic16_t;
+typedef int_fast16_t atomic_fast16_t;
+typedef uint_fast16_t uatomic_fast16_t;
+
+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;
+
+
+#define __arch_compare_and_exchange_8_acq(mem, newval, oldval) \
+  (abort (), 0)
+
+#define __arch_compare_and_exchange_16_acq(mem, newval, oldval) \
+  (abort (), 0)
+
+#ifdef UP
+#define __ARCH_ACQ_INSTR       ""
+#define __ARCH_REL_INSTR       ""
+#else
+#define __ARCH_ACQ_INSTR       "isync"
+#define __ARCH_REL_INSTR       "sync"
+#endif
+
+/*
+ * XXX At present these have both acquire and release semantics.
+ * Ultimately we should do separate _acq and _rel versions.
+ */
+
+/*
+ * XXX this may not work properly on 64-bit if the register
+ * containing oldval has the high half non-zero for some reason.
+ */
+#define __arch_compare_and_exchange_32_acq(mem, newval, oldval)        \
+({                                                             \
+  unsigned int __tmp;                                          \
+  __asm __volatile (__ARCH_REL_INSTR "\n"                      \
+                   "1: lwarx   %0,0,%1\n"                      \
+                   "   subf.   %0,%2,%0\n"                     \
+                   "   bne     2f\n"                           \
+                   "   stwcx.  %3,0,%1\n"                      \
+                   "   bne-    1b\n"                           \
+                   "2: " __ARCH_ACQ_INSTR                      \
+                   : "=&r" (__tmp)                             \
+                   : "r" (mem), "r" (oldval), "r" (newval)     \
+                   : "cr0", "memory");                         \
+  __tmp != 0;                                                  \
+})
+
+#ifdef __powerpc64__
+#define __arch_compare_and_exchange_64_acq(mem, newval, oldval)        \
+({                                                             \
+  unsigned long        __tmp;                                          \
+  __asm __volatile (__ARCH_REL_INSTR "\n"                      \
+                   "1: ldarx   %0,0,%1\n"                      \
+                   "   subf.   %0,%2,%0\n"                     \
+                   "   bne     2f\n"                           \
+                   "   stdcx.  %3,0,%1\n"                      \
+                   "   bne-    1b\n"                           \
+                   "2: " __ARCH_ACQ_INSTR                      \
+                   : "=&r" (__tmp)                             \
+                   : "r" (mem), "r" (oldval), "r" (newval)     \
+                   : "cr0", "memory");                         \
+  __tmp != 0;                                                  \
+})
+
+#else /* powerpc32 */
+#define __arch_compare_and_exchange_64_acq(mem, newval, oldval) \
+  (abort (), 0)
+#endif
+
+#define atomic_full_barrier()  __asm ("sync" ::: "memory")
+#ifdef __powerpc64__
+#define atomic_read_barrier()  __asm ("lwsync" ::: "memory")
+#else
+#define atomic_read_barrier()  __asm ("sync" ::: "memory")
+#endif
+#define atomic_write_barrier() __asm ("eieio" ::: "memory")
diff --git a/nptl/sysdeps/powerpc/pthread_spin_lock.c b/nptl/sysdeps/powerpc/pthread_spin_lock.c
new file mode 100644 (file)
index 0000000..e2293fd
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.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"
+
+int
+pthread_spin_lock (lock)
+     pthread_spinlock_t *lock;
+{
+  unsigned int __tmp;
+
+  asm volatile (
+       "1:     lwarx   %0,0,%1\n"
+       "       cmpwi   0,%0,0\n"
+       "       bne-    2f\n"
+       "       stwcx.  %2,0,%1\n"
+       "       bne-    2f\n"
+       "       isync\n"
+       "       .subsection 1\n"
+       "2:     lwzx    %0,0,%1\n"
+       "       cmpwi   0,%0,0\n"
+       "       bne     2b\n"
+       "       b       1b\n"
+       "       .previous"
+       : "=&r" (__tmp)
+       : "r" (lock), "r" (1)
+       : "cr0", "memory");
+  return 0;
+}
diff --git a/nptl/sysdeps/powerpc/pthread_spin_trylock.c b/nptl/sysdeps/powerpc/pthread_spin_trylock.c
new file mode 100644 (file)
index 0000000..d8e1dbc
--- /dev/null
@@ -0,0 +1,43 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.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 <errno.h>
+#include "pthreadP.h"
+
+int
+pthread_spin_trylock (lock)
+     pthread_spinlock_t *lock;
+{
+  unsigned int old;
+  int err = EBUSY;
+
+  asm ("1:     lwarx   %0,0,%2\n"
+       "       cmpwi   0,%0,0\n"
+       "       bne     2f\n"
+       "       stwcx.  %3,0,%2\n"
+       "       bne-    1b\n"
+       "       li      %1,0\n"
+       "       isync\n"
+       "2:     "
+       : "=&r" (old), "=&r" (err)
+       : "r" (lock), "r" (1), "1" (err)
+       : "cr0", "memory");
+
+  return err;
+}
diff --git a/nptl/sysdeps/powerpc/pthreaddef.h b/nptl/sysdeps/powerpc/pthreaddef.h
new file mode 100644 (file)
index 0000000..b28d0be
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (C) 2003 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        (4 * 1024 * 1024)
+
+/* Required stack pointer alignment at beginning.  The ABI requires 16
+   bytes (for both 32-bit and 64-bit PowerPC).  */
+#define STACK_ALIGN            16
+
+/* Minimal stack size after allocating thread descriptor and guard size.  */
+#define MINIMAL_REST_STACK     4096
+
+/* Alignment requirement for TCB.  */
+#define TCB_ALIGNMENT          16
+
+/* The signal used for asynchronous cancelation.  */
+#define SIGCANCEL              __SIGRTMIN
+
+
+/* Location of current stack frame.  */
+#define CURRENT_STACK_FRAME    __builtin_frame_address (0)
+
+
+/* XXX Until we have a better place keep the definitions here.  */
+
+/* While there is no such syscall.  */
+#define __exit_thread_inline(val) \
+  INLINE_SYSCALL (exit, 1, (val))
diff --git a/nptl/sysdeps/powerpc/tcb-offsets.sym b/nptl/sysdeps/powerpc/tcb-offsets.sym
new file mode 100644 (file)
index 0000000..d6b7560
--- /dev/null
@@ -0,0 +1,13 @@
+#include <sysdep.h>
+#include <tls.h>
+
+--
+
+-- Abuse tls.h macros to derive offsets relative to the thread register.
+# undef __thread_register
+# define __thread_register     ((void *) 0)
+# define thread_offsetof(mem)  ((void *) &THREAD_SELF->mem - (void *) 0)
+
+#if TLS_MULTIPLE_THREADS_IN_TCB
+MULTIPLE_THREADS_OFFSET                thread_offsetof (header.multiple_threads)
+#endif
diff --git a/nptl/sysdeps/powerpc/td_ta_map_lwp2thr.c b/nptl/sysdeps/powerpc/td_ta_map_lwp2thr.c
new file mode 100644 (file)
index 0000000..d1a9368
--- /dev/null
@@ -0,0 +1,44 @@
+/* Which thread is running on an LWP?  PowerPC version.
+   Copyright (C) 2003 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 "thread_dbP.h"
+#include <tls.h>
+
+
+td_err_e
+td_ta_map_lwp2thr (const td_thragent_t *ta, lwpid_t lwpid, td_thrhandle_t *th)
+{
+  LOG ("td_ta_map_lwp2thr");
+
+  /* Test whether the TA parameter is ok.  */
+  if (! ta_ok (ta))
+    return TD_BADTA;
+
+  prgregset_t regs;
+  if (ps_lgetregs (ta->ph, lwpid, regs) != PS_OK)
+    return TD_ERR;
+
+  th->th_unique = ((void *) regs[PT_THREAD_POINTER]
+                  - TLS_TCB_OFFSET - TLS_TCB_SIZE - TLS_PRE_TCB_SIZE);
+
+  /* Found it.  Now complete the `td_thrhandle_t' object.  */
+  th->th_ta_p = (td_thragent_t *) ta;
+
+  return TD_OK;
+}
diff --git a/nptl/sysdeps/powerpc/tls.h b/nptl/sysdeps/powerpc/tls.h
new file mode 100644 (file)
index 0000000..04d76a6
--- /dev/null
@@ -0,0 +1,152 @@
+/* Definition for thread-local data handling.  NPTL/PowerPC version.
+   Copyright (C) 2003 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 <stddef.h>
+# include <stdint.h>
+
+/* Type for the dtv.  */
+typedef union dtv
+{
+  size_t counter;
+  void *pointer;
+} dtv_t;
+
+#else /* __ASSEMBLER__ */
+# include <tcb-offsets.h>
+#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
+
+/* For 32-bit, we use the multiple_threads field in the pthread struct */
+#ifndef __powerpc64__
+# define TLS_MULTIPLE_THREADS_IN_TCB   1
+#endif
+
+/* Get the thread descriptor definition.  */
+# include <nptl/descr.h>
+
+/* 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;
+} tcbhead_t;
+
+/* This is the size of the initial TCB.  */
+# define TLS_INIT_TCB_SIZE     sizeof (tcbhead_t)
+
+/* Alignment requirements for the initial TCB.  */
+# define TLS_INIT_TCB_ALIGN    __alignof__ (tcbhead_t)
+
+/* This is the size of the TCB.  */
+# define TLS_TCB_SIZE          sizeof (tcbhead_t)
+
+/* Alignment requirements for the TCB.  */
+# define TLS_TCB_ALIGN         __alignof__ (tcbhead_t)
+
+/* This is the size we need before TCB.  */
+# define TLS_PRE_TCB_SIZE      sizeof (struct pthread)
+
+/* XXX if __alignof__ (struct pthread) > __alignof (tcbhead_t)
+   we could be in trouble.  -- paulus */
+
+# ifndef __powerpc64__
+/* Register r2 (tp) is reserved by the ABI as "thread pointer". */
+register void *__thread_register __asm__ ("r2");
+#  define PT_THREAD_POINTER PT_R2
+# else
+/* Register r13 (tp) is reserved by the ABI as "thread pointer". */
+register void *__thread_register __asm__ ("r13");
+#  define PT_THREAD_POINTER PT_R13
+# endif
+
+/* The following assumes that TP (R2 or R13) points to the end of the
+   TCB + 0x7000 (per the ABI).  This implies that TCB address is
+   TP-(TLS_TCB_SIZE + 0x7000).  As we define TLS_DTV_AT_TP we can
+   assume that the pthread struct is allocated immediately ahead of the
+   TCB.  This implies that the pthread_descr address is
+   TP-(TLS_PRE_TCB_SIZE + TLS_TCB_SIZE + 0x7000).  */
+# 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))->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))->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) \
+    (__thread_register = (void *) (tcbp) + TLS_TCB_OFFSET + TLS_TCB_SIZE, NULL)
+
+/* Return the address of the dtv for the current thread.  */
+# define THREAD_DTV() \
+     (((tcbhead_t *) (__thread_register - TLS_TCB_OFFSET - TLS_TCB_SIZE))->dtv)
+
+/* Return the thread descriptor for the current thread.  */
+# define THREAD_SELF \
+    ((struct pthread *) (__thread_register \
+                        - TLS_TCB_OFFSET - TLS_TCB_SIZE - TLS_PRE_TCB_SIZE))
+
+/* Read member of the thread descriptor directly.  */
+# define THREAD_GETMEM(descr, member) ((void)(descr), (THREAD_SELF)->member)
+
+/* Same as THREAD_GETMEM, but the member offset can be non-constant.  */
+# define THREAD_GETMEM_NC(descr, member, idx) \
+    ((void)(descr), (THREAD_SELF)->member[idx])
+
+/* Set member of the thread descriptor directly.  */
+# define THREAD_SETMEM(descr, member, value) \
+    ((void)(descr), (THREAD_SELF)->member = (value))
+
+/* Same as THREAD_SETMEM, but the member offset can be non-constant.  */
+# define THREAD_SETMEM_NC(descr, member, idx, value) \
+    ((void)(descr), (THREAD_SELF)->member[idx] = (value))
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* tls.h */
diff --git a/nptl/sysdeps/pthread/pthread_spin_init.c b/nptl/sysdeps/pthread/pthread_spin_init.c
new file mode 100644 (file)
index 0000000..c227508
--- /dev/null
@@ -0,0 +1,28 @@
+/* pthread_spin_init -- initialize a spin lock.  Generic version.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.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"
+
+int
+pthread_spin_init (pthread_spinlock_t *lock, int pshared)
+{
+  *lock = 0;
+  return 0;
+}
diff --git a/nptl/sysdeps/pthread/pthread_spin_unlock.c b/nptl/sysdeps/pthread/pthread_spin_unlock.c
new file mode 100644 (file)
index 0000000..f97cadf
--- /dev/null
@@ -0,0 +1,30 @@
+/* pthread_spin_unlock -- unlock a spin lock.  Generic version.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.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 <atomic.h>
+
+int
+pthread_spin_unlock (pthread_spinlock_t *lock)
+{
+  atomic_full_barrier ();
+  *lock = 0;
+  return 0;
+}
diff --git a/nptl/sysdeps/unix/sysv/linux/libc-lowlevellock.c b/nptl/sysdeps/unix/sysv/linux/libc-lowlevellock.c
new file mode 100644 (file)
index 0000000..b192822
--- /dev/null
@@ -0,0 +1,21 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.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.  */
+
+/* No difference to lowlevellock.c, except we lose a couple of functions.  */
+#include "lowlevellock.c"
diff --git a/nptl/sysdeps/unix/sysv/linux/libc-lowlevelmutex.c b/nptl/sysdeps/unix/sysv/linux/libc-lowlevelmutex.c
new file mode 100644 (file)
index 0000000..7c594e3
--- /dev/null
@@ -0,0 +1 @@
+/* Nothing needed here in fact.  */
diff --git a/nptl/sysdeps/unix/sysv/linux/lowlevellock.c b/nptl/sysdeps/unix/sysv/linux/lowlevellock.c
new file mode 100644 (file)
index 0000000..b80e153
--- /dev/null
@@ -0,0 +1,140 @@
+/* low level locking for pthread library.  Generic futex-using version.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.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 <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <sys/time.h>
+
+
+void
+__lll_lock_wait (int *futex, int val)
+{
+  do {
+      lll_futex_wait (futex, val+1);
+  } while ((val = __lll_add (futex, 1)) != 0);
+  *futex = 2;
+}
+hidden_proto (__lll_lock_wait)
+
+
+int
+__lll_timedlock_wait (int *futex, int val, const struct timespec *abstime)
+{
+  int err;
+
+  /* Reject invalid timeouts.  */
+  if (abstime->tv_nsec >= 1000000000)
+    return EINVAL;
+
+  do
+    {
+      struct timeval tv;
+      struct timespec rt;
+      int sec, nsec;
+
+      /* Get the current time.  */
+      __gettimeofday (&tv, NULL);
+
+      /* Compute relative timeout.  */
+      sec = abstime->tv_sec - tv.tv_sec;
+      nsec = abstime->tv_nsec - tv.tv_usec * 1000;
+      if (nsec < 0)
+       {
+         nsec += 1000000000;
+         --sec;
+       }
+
+      /* Already timed out?  */
+      err = -ETIMEDOUT;
+      if (sec < 0)
+       break;
+
+      /* Wait.  */
+      rt.tv_sec = sec;
+      rt.tv_nsec = nsec;
+      err = lll_futex_timed_wait (futex, val+1, &rt);
+    } while (err == 0 && (val = __lll_add (futex, 1)) != 0);
+
+  *futex = 2;
+  return -err;
+}
+hidden_proto (__lll_timedlock_wait)
+
+
+/* These don't get included in libc.so  */
+#ifdef IS_IN_libpthread
+int
+lll_unlock_wake_cb (int *futex)
+{
+  __lll_add (futex, 1);
+  return 0;
+}
+hidden_proto (lll_unlock_wake_cb)
+
+
+int
+__lll_timedwait_tid (int *tidp, const struct timespec *abstime)
+{
+  int tid;
+  int err = 0;
+
+  if (abstime == NULL || abstime->tv_nsec >= 1000000000)
+    return EINVAL;
+
+  /* Repeat until thread terminated.  */
+  while ((tid = *tidp) != 0)
+    {
+      struct timeval tv;
+      struct timespec rt;
+      int sec, nsec;
+
+      /* Get the current time.  */
+      __gettimeofday (&tv, NULL);
+
+      /* Compute relative timeout.  */
+      sec = abstime->tv_sec - tv.tv_sec;
+      nsec = abstime->tv_nsec - tv.tv_usec * 1000;
+      if (nsec < 0)
+       {
+         nsec += 1000000000;
+         --sec;
+       }
+
+      /* Already timed out?  */
+      err = -ETIMEDOUT;
+      if (sec < 0)
+       break;
+
+      /* Wait.  */
+      rt.tv_sec = sec;
+      rt.tv_nsec = nsec;
+
+      /* Wait until thread terminates.  */
+      err = lll_futex_timed_wait (tidp, tid, &rt);
+      if (err != 0)
+       break;
+    }
+
+  return -err;
+}
+
+hidden_proto (__lll_timedwait_tid)
+#endif
diff --git a/nptl/sysdeps/unix/sysv/linux/powerpc/Makefile b/nptl/sysdeps/unix/sysv/linux/powerpc/Makefile
new file mode 100644 (file)
index 0000000..e98c9bd
--- /dev/null
@@ -0,0 +1,2 @@
+# pull in __syscall_error routine
+libpthread-routines += sysdep
diff --git a/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h
new file mode 100644 (file)
index 0000000..332f50f
--- /dev/null
@@ -0,0 +1,167 @@
+/* Machine-specific pthread type layouts.  PowerPC version.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.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.  */
+
+#ifndef _BITS_PTHREADTYPES_H
+#define _BITS_PTHREADTYPES_H   1
+
+#include <bits/wordsize.h>
+
+#if __WORDSIZE == 64
+# 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 struct __opaque_pthread *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;
+    struct pthread *__owner;
+    /* KIND must stay at this position in the structure to maintain
+       binary compatibility.  */
+    int __kind;
+  } __data;
+  char __size[__SIZEOF_PTHREAD_MUTEX_T];
+  long int __align;
+} pthread_mutex_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_MUTEXATTR_T];
+  long 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;
+    int __pad;
+    unsigned long long int __total_seq;
+    unsigned long long int __wakeup_seq;
+    unsigned long long int __woken_seq;
+  } __data;
+  char __size[__SIZEOF_PTHREAD_COND_T];
+  long int __align;
+} pthread_cond_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_CONDATTR_T];
+  long int __align;
+} pthread_condattr_t;
+
+
+/* Keys for thread-specific data */
+typedef unsigned int pthread_key_t;
+
+
+/* Once-only execution */
+typedef int pthread_once_t;
+
+
+#ifdef __USE_UNIX98
+/* Data structure for read-write lock variable handling.  The
+   structure of the attribute type is deliberately not exposed.  */
+typedef union
+{
+  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;
+    pthread_t __writer;
+    /* FLAGS must stay at this position in the structure to maintain
+       binary compatibility.  */
+    unsigned int __flags;
+  } __data;
+  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/powerpc/bits/semaphore.h b/nptl/sysdeps/unix/sysv/linux/powerpc/bits/semaphore.h
new file mode 100644 (file)
index 0000000..02100d1
--- /dev/null
@@ -0,0 +1,44 @@
+/* Machine-specific POSIX semaphore type layouts.  PowerPC version.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.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.  */
+
+#ifndef _SEMAPHORE_H
+# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead."
+#endif
+
+#include <bits/wordsize.h>
+
+#if __WORDSIZE == 64
+# 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   ((int) ((~0u) >> 1))
+
+
+typedef union
+{
+  char __size[__SIZEOF_SEM_T];
+  long int __align;
+} sem_t;
diff --git a/nptl/sysdeps/unix/sysv/linux/powerpc/createthread.c b/nptl/sysdeps/unix/sysv/linux/powerpc/createthread.c
new file mode 100644 (file)
index 0000000..bcbcdd7
--- /dev/null
@@ -0,0 +1,25 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.com>.
+
+   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_TCB_SIZE + TLS_PRE_TCB_SIZE)
+
+/* Get the real implementation.         */
+#include <nptl/sysdeps/pthread/createthread.c>
diff --git a/nptl/sysdeps/unix/sysv/linux/powerpc/fork.c b/nptl/sysdeps/unix/sysv/linux/powerpc/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/powerpc/lowlevellock.h b/nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h
new file mode 100644 (file)
index 0000000..3295b63
--- /dev/null
@@ -0,0 +1,224 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.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 Libr   \ary; 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>
+
+#define __NR_futex             221
+#define FUTEX_WAIT             0
+#define FUTEX_WAKE             1
+
+/* 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: 0;                \
+  })
+
+#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: 0;                        \
+  })
+
+#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: 0;                \
+  })
+
+#ifdef UP
+#define __lll_acq_instr        ""
+#define __lll_rel_instr        ""
+#else
+#define __lll_acq_instr        "isync"
+#define __lll_rel_instr        "sync"
+#endif
+
+/* Set *futex to 1 if it is 0, atomically.  Returns the old value */
+#define __lll_trylock(futex)                           \
+  ({ int __val;                                                        \
+     __asm __volatile ("1:     lwarx   %0,0,%2\n"              \
+                      "        cmpwi   0,%0,0\n"               \
+                      "        bne     2f\n"                   \
+                      "        stwcx.  %3,0,%2\n"              \
+                      "        bne-    1b\n"                   \
+                      "2:      " __lll_acq_instr               \
+                      : "=&r" (__val), "=m" (*futex)           \
+                      : "r" (futex), "r" (1), "1" (*futex)     \
+                      : "cr0", "memory");                      \
+     __val;                                                    \
+  })
+
+#define lll_mutex_trylock(lock)        __lll_trylock(&(lock))
+
+/* Add inc to *futex atomically and return the old value. */
+#define __lll_add(futex, inc)                                          \
+  ({ int __val, __tmp;                                                 \
+     __asm __volatile ("1:     lwarx   %0,0,%3\n"                      \
+                      "        addi    %1,%0,%4\n"                     \
+                      "        stwcx.  %1,0,%3\n"                      \
+                      "        bne-    1b"                             \
+                      : "=&b" (__val), "=&r" (__tmp), "=m" (*futex)    \
+                      : "r" (futex), "I" (inc), "2" (*futex)           \
+                      : "cr0");                                        \
+     __val;                                                            \
+  })
+
+extern void __lll_lock_wait (int *futex, int val) attribute_hidden;
+
+#define lll_mutex_lock(lock)                           \
+  (void) ({                                            \
+    int *__futex = &(lock);                            \
+    int __val = __lll_add (__futex, 1);                        \
+    __asm __volatile (__lll_acq_instr ::: "memory");   \
+    if (__builtin_expect (__val != 0, 0))              \
+      __lll_lock_wait (__futex, __val);                        \
+  })
+
+extern int __lll_timedlock_wait
+       (int *futex, int val, const struct timespec *) attribute_hidden;
+
+#define lll_mutex_timedlock(lock, abstime)                     \
+  ({ int *__futex = &(lock);                                           \
+     int __val = __lll_add (__futex, 1);                               \
+     __asm __volatile (__lll_acq_instr ::: "memory");                  \
+     if (__builtin_expect (__val != 0, 0))                             \
+       __val = __lll_timedlock_wait (__futex, __val, (abstime));       \
+     __val;                                                            \
+  })
+
+#define lll_mutex_unlock(lock)                         \
+  (void) ({                                            \
+    int *__futex = &(lock);                            \
+     __asm __volatile (__lll_rel_instr ::: "memory");  \
+    int __val = __lll_add (__futex, -1);               \
+    if (__builtin_expect (__val != 1, 0))              \
+      {                                                        \
+       *__futex = 0;                                   \
+       lll_futex_wake (__futex, 1);                    \
+      }                                                        \
+  })
+
+#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;                                             \
+  })
+
+
+/* Decrement *futex if it is > 0, and return the old value */
+#define __lll_dec_if_positive(futex)                                   \
+  ({ int __val, __tmp;                                                 \
+     __asm __volatile ("1:     lwarx   %0,0,%3\n"                      \
+                      "        cmpwi   0,%0,0\n"                       \
+                      "        addi    %1,%0,-1\n"                     \
+                      "        ble     2f\n"                           \
+                      "        stwcx.  %1,0,%3\n"                      \
+                      "        bne-    1b\n"                           \
+                      "2:      " __lll_acq_instr                       \
+                      : "=&b" (__val), "=&r" (__tmp), "=m" (*futex)    \
+                      : "r" (futex), "2" (*futex)                      \
+                      : "cr0");                                        \
+     __val;                                                            \
+  })
+
+
+/* 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/powerpc/powerpc32/sysdep-cancel.h b/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h
new file mode 100644 (file)
index 0000000..d256f8d
--- /dev/null
@@ -0,0 +1,102 @@
+/* Cancellable system call stubs.  Linux/PowerPC version.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Franz Sirl <Franz.Sirl-kernel@lauterbach.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 <sysdep.h>
+#include <tls.h>
+#ifndef __ASSEMBLER__
+# include <nptl/pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args)                              \
+  .section ".text";                                                    \
+  ENTRY (name)                                                         \
+    SINGLE_THREAD_P;                                                   \
+    bne- .Lpseudo_cancel;                                              \
+    DO_CALL (SYS_ify (syscall_name));                                  \
+    PSEUDO_RET;                                                                \
+  .Lpseudo_cancel:                                                     \
+    stwu 1,-48(1);                                                     \
+    mflr 9;                                                            \
+    stw 9,52(1);                                                       \
+    DOCARGS_##args;    /* save syscall args around CENABLE.  */        \
+    CENABLE;                                                           \
+    stw 3,16(1);       /* store CENABLE return value (MASK).  */       \
+    UNDOCARGS_##args;  /* restore syscall args.  */                    \
+    DO_CALL (SYS_ify (syscall_name));                                  \
+    mfcr 0;            /* save CR/R3 around CDISABLE.  */              \
+    stw 3,8(1);                                                                \
+    stw 0,12(1);                                                       \
+    lwz 3,16(1);       /* pass MASK to CDISABLE.  */                   \
+    CDISABLE;                                                          \
+    lwz 4,52(1);                                                       \
+    lwz 0,12(1);       /* restore CR/R3. */                            \
+    lwz 3,8(1);                                                                \
+    mtlr 4;                                                            \
+    mtcr 0;                                                            \
+    addi 1,1,48;
+
+# define DOCARGS_0
+# define UNDOCARGS_0
+
+# define DOCARGS_1     stw 3,20(1); DOCARGS_0
+# define UNDOCARGS_1   lwz 3,20(1); UNDOCARGS_0
+
+# define DOCARGS_2     stw 4,24(1); DOCARGS_1
+# define UNDOCARGS_2   lwz 4,24(1); UNDOCARGS_1
+
+# define DOCARGS_3     stw 5,28(1); DOCARGS_2
+# define UNDOCARGS_3   lwz 5,28(1); UNDOCARGS_2
+
+# define DOCARGS_4     stw 6,32(1); DOCARGS_3
+# define UNDOCARGS_4   lwz 6,32(1); UNDOCARGS_3
+
+# define DOCARGS_5     stw 7,36(1); DOCARGS_4
+# define UNDOCARGS_5   lwz 7,36(1); UNDOCARGS_4
+
+# define DOCARGS_6     stw 8,40(1); DOCARGS_5
+# define UNDOCARGS_6   lwz 8,40(1); UNDOCARGS_5
+
+# ifdef IS_IN_libpthread
+#  define CENABLE      bl JUMPTARGET(__pthread_enable_asynccancel)
+#  define CDISABLE     bl JUMPTARGET(__pthread_disable_asynccancel)
+# else
+#  define CENABLE      bl JUMPTARGET(__libc_enable_asynccancel)
+#  define CDISABLE     bl JUMPTARGET(__libc_disable_asynccancel)
+# endif
+
+# ifndef __ASSEMBLER__
+#  define SINGLE_THREAD_P                                              \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF,                                \
+                                  header.multiple_threads) == 0, 1)
+# else
+#  define SINGLE_THREAD_P                                              \
+  lwz 10,MULTIPLE_THREADS_OFFSET(2);                                   \
+  cmpwi 10,0
+# endif
+
+#elif !defined __ASSEMBLER__
+
+/* This code should never be used but we define it anyhow.  */
+# define SINGLE_THREAD_P (1)
+
+#endif
diff --git a/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h b/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h
new file mode 100644 (file)
index 0000000..4a6cbf0
--- /dev/null
@@ -0,0 +1,102 @@
+/* Cancellable system call stubs.  Linux/PowerPC64 version.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Franz Sirl <Franz.Sirl-kernel@lauterbach.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 <sysdep.h>
+#include <tls.h>
+#ifndef __ASSEMBLER__
+# include <nptl/pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args)                              \
+  .section ".text";                                                    \
+  ENTRY (name)                                                         \
+    SINGLE_THREAD_P;                                                   \
+    bne- .Lpseudo_cancel;                                              \
+    DO_CALL (SYS_ify (syscall_name));                                  \
+    PSEUDO_RET;                                                                \
+  .Lpseudo_cancel:                                                     \
+    stdu 1,-128(1);                                                    \
+    mflr 9;                                                            \
+    std  9,128+16(1);                                                  \
+    DOCARGS_##args;    /* save syscall args around CENABLE.  */        \
+    CENABLE;                                                           \
+    std  3,72(1);      /* store CENABLE return value (MASK).  */       \
+    UNDOCARGS_##args;  /* restore syscall args.  */                    \
+    DO_CALL (SYS_ify (syscall_name));                                  \
+    mfcr 0;            /* save CR/R3 around CDISABLE.  */              \
+    std  3,64(1);                                                              \
+    std  0,8(1);                                                       \
+    ld   3,72(1);      /* pass MASK to CDISABLE.  */                   \
+    CDISABLE;                                                          \
+    ld   9,128+16(1);                                                  \
+    ld   0,8(1);       /* restore CR/R3. */                            \
+    ld   3,64(1);                                                              \
+    mtlr 9;                                                            \
+    mtcr 0;                                                            \
+    addi 1,1,128;
+
+# define DOCARGS_0
+# define UNDOCARGS_0
+
+# define DOCARGS_1     std 3,80(1); DOCARGS_0
+# define UNDOCARGS_1   ld 3,80(1); UNDOCARGS_0
+
+# define DOCARGS_2     std 4,88(1); DOCARGS_1
+# define UNDOCARGS_2   ld 4,88(1); UNDOCARGS_1
+
+# define DOCARGS_3     std 5,96(1); DOCARGS_2
+# define UNDOCARGS_3   ld 5,96(1); UNDOCARGS_2
+
+# define DOCARGS_4     std 6,104(1); DOCARGS_3
+# define UNDOCARGS_4   ld 6,104(1); UNDOCARGS_3
+
+# define DOCARGS_5     std 7,112(1); DOCARGS_4
+# define UNDOCARGS_5   ld 7,112(1); UNDOCARGS_4
+
+# define DOCARGS_6     std 8,120(1); DOCARGS_5
+# define UNDOCARGS_6   ld 8,120(1); UNDOCARGS_5
+
+# ifdef IS_IN_libpthread
+#  define CENABLE      bl JUMPTARGET(__pthread_enable_asynccancel)
+#  define CDISABLE     bl JUMPTARGET(__pthread_disable_asynccancel)
+# else
+#  define CENABLE      bl JUMPTARGET(__libc_enable_asynccancel)
+#  define CDISABLE     bl JUMPTARGET(__libc_disable_asynccancel)
+# endif
+
+# ifndef __ASSEMBLER__
+#  define SINGLE_THREAD_P                                              \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, multiple_threads) \
+                   == 0, 1)
+# else
+#   define SINGLE_THREAD_P                                             \
+  lwz   10,MULTIPLE_THREADS_OFFSET(13);                                \
+  cmpdi 10,0
+# endif
+
+#elif !defined __ASSEMBLER__
+
+/* This code should never be used but we define it anyhow.  */
+# define SINGLE_THREAD_P (1)
+
+#endif
diff --git a/nptl/sysdeps/unix/sysv/linux/powerpc/pt-vfork.S b/nptl/sysdeps/unix/sysv/linux/powerpc/pt-vfork.S
new file mode 100644 (file)
index 0000000..46e33c0
--- /dev/null
@@ -0,0 +1,35 @@
+/* Copyright (C) 2003 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-cancel.h>
+#define _ERRNO_H       1
+#include <bits/errno.h>
+#include <kernel-features.h>
+
+/* Clone the calling process, but without copying the whole address space.
+   The calling process is suspended until the new process exits or is
+   replaced by a call to `execve'.  Return -1 for errors, 0 to the new process,
+   and the process ID of the new process to the old process.  */
+
+ENTRY (__vfork)
+       DO_CALL (SYS_ify (vfork));
+       PSEUDO_RET
+
+PSEUDO_END (__vfork)
+
+weak_alias (__vfork, vfork)
diff --git a/nptl/sysdeps/unix/sysv/linux/powerpc/pthread_once.c b/nptl/sysdeps/unix/sysv/linux/powerpc/pthread_once.c
new file mode 100644 (file)
index 0000000..18029e9
--- /dev/null
@@ -0,0 +1,99 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.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 (pthread_once_t *once_control, void (*init_routine) (void))
+{
+  for (;;)
+    {
+      int oldval;
+      int newval;
+      int tmp;
+
+      /* Pseudo code:
+        newval = __fork_generation | 1;
+        oldval = *once_control;
+        if ((oldval & 2) == 0)
+          *once_control = newval;
+        Do this atomically.
+      */
+      newval = __fork_generation | 1;
+      __asm __volatile ("1:    lwarx   %0,0,%3\n"
+                       "       andi.   %1,%0,2\n"
+                       "       bne     2f\n"
+                       "       stwcx.  %4,0,%3\n"
+                       "2:     isync"
+                       : "=&r" (oldval), "=&r" (tmp), "=m" (*once_control)
+                       : "r" (once_control), "r" (newval), "m" (*once_control)
+                       : "cr0");
+
+      /* Check if the initializer has already been done.  */
+      if ((oldval & 2) != 0)
+       return 0;
+
+      /* Check if another thread already runs the initializer. */
+      if ((oldval & 1) == 0)
+       break;
+
+      /* Check whether the initializer execution was interrupted by a fork.  */
+      if (oldval != newval)
+       break;
+
+      /* Same generation, some other thread was faster. Wait.  */
+      lll_futex_wait (once_control, oldval);
+    }
+
+
+  /* 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 to take the bottom 2 bits from 01 to 10.  */
+  __lll_add (once_control, 1);
+
+  /* Wake up all other threads.  */
+  lll_futex_wake (once_control, INT_MAX);
+
+  return 0;
+}
+weak_alias (__pthread_once, pthread_once)
+strong_alias (__pthread_once, __pthread_once_internal)
diff --git a/nptl/sysdeps/unix/sysv/linux/sem_post.c b/nptl/sysdeps/unix/sysv/linux/sem_post.c
new file mode 100644 (file)
index 0000000..77defc8
--- /dev/null
@@ -0,0 +1,47 @@
+/* sem_post -- post to a POSIX semaphore.  Generic futex-using version.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.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 <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <internaltypes.h>
+#include <semaphore.h>
+
+#include <shlib-compat.h>
+
+int
+__new_sem_post (sem_t *sem)
+{
+  int *futex = (int *) sem;
+  int err, nr;
+
+  __asm __volatile (__lll_rel_instr ::: "memory");
+  nr = __lll_add (futex, 1);
+  err = lll_futex_wake (futex, nr);
+  if (err == 0)
+    return 0;
+  __set_errno (-err);
+  return -1;
+}
+versioned_symbol (libpthread, __new_sem_post, sem_post, GLIBC_2_1);
+#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_1)
+strong_alias (__new_sem_post, __old_sem_post)
+compat_symbol (libpthread, __old_sem_post, sem_post, GLIBC_2_0);
+#endif
diff --git a/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c b/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c
new file mode 100644 (file)
index 0000000..e1b32f4
--- /dev/null
@@ -0,0 +1,87 @@
+/* sem_timedwait -- wait on a semaphore.  Generic futex-using version.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.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 <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <internaltypes.h>
+#include <semaphore.h>
+
+#include <shlib-compat.h>
+
+
+int
+sem_timedwait (sem_t *sem, const struct timespec *abstime)
+{
+  int *futex = (int *) sem;
+  int val;
+  int err;
+
+  if (*futex > 0)
+    {
+      val = __lll_dec_if_positive (futex);
+      if (val > 0)
+       return 0;
+    }
+
+  err = -EINVAL;
+  if (abstime->tv_nsec >= 1000000000)
+    goto error_return;
+
+  do
+    {
+      struct timeval tv;
+      struct timespec rt;
+      int sec, nsec;
+
+      /* Get the current time.  */
+      __gettimeofday (&tv, NULL);
+
+      /* Compute relative timeout.  */
+      sec = abstime->tv_sec - tv.tv_sec;
+      nsec = abstime->tv_nsec - tv.tv_usec * 1000;
+      if (nsec < 0)
+       {
+         nsec += 1000000000;
+         --sec;
+       }
+
+      /* Already timed out?  */
+      err = -ETIMEDOUT;
+      if (sec < 0)
+       goto error_return;
+
+      /* Do wait.  */
+      rt.tv_sec = sec;
+      rt.tv_nsec = nsec;
+      err = lll_futex_timed_wait (futex, 0, &rt);
+      if (err != 0 && err != -EWOULDBLOCK)
+       goto error_return;
+
+      val = __lll_dec_if_positive (futex);
+    }
+  while (val <= 0);
+
+  return 0;
+
+ error_return:
+  __set_errno (-err);
+  return -1;
+}
diff --git a/nptl/sysdeps/unix/sysv/linux/sem_trywait.c b/nptl/sysdeps/unix/sysv/linux/sem_trywait.c
new file mode 100644 (file)
index 0000000..a7b60a1
--- /dev/null
@@ -0,0 +1,50 @@
+/* sem_trywait -- wait on a semaphore.  Generic futex-using version.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.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 <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <internaltypes.h>
+#include <semaphore.h>
+
+#include <shlib-compat.h>
+
+
+int
+__new_sem_trywait (sem_t *sem)
+{
+  int *futex = (int *) sem;
+  int val;
+
+  if (*futex > 0)
+    {
+      val = __lll_dec_if_positive (futex);
+      if (val > 0)
+       return 0;
+    }
+
+  __set_errno (EAGAIN);
+  return -1;
+}
+versioned_symbol (libpthread, __new_sem_trywait, sem_trywait, GLIBC_2_1);
+#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_1)
+strong_alias (__new_sem_trywait, __old_sem_trywait)
+compat_symbol (libpthread, __old_sem_trywait, sem_trywait, GLIBC_2_0);
+#endif