This is the mail archive of the libc-hacker@sourceware.org mailing list for the glibc project.

Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] NPTL SPARC pre-v9 support


Hi!

The following patch (almost) implements what has been outlined in
https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=161736
The major changes from that outline are that it should (am still verifying
that) cause no changes whatsoever for sparcv9 or sparc64 built glibc,
sparc built glibc's shared libraries expected to work properly just on
pre-v9 CPUs and sparc built .a libraries (and therefore statically linked
32-bit binaries too) be able to cope with both, by using CAS on 64-bit
CPUs and various hacks on 32-bit CPUs.

So far I have done sparc-linux NPTL build and make check (worked fine),
am sparcv9-linux NPTL build and make check, plus verified that stripped
libc.so/libpthread.so are identical on sparcv9-linux without and with this
patch.

As written in the outline, on pre-v9 CPUs it uses the ldstub lock pool
indexed by hashed address for most of the atomic stuff, ldstub lock
in the upper 8 bits of the 32-bit value for locks (where only 0, 1 and 2
are valid values (but anything < 16M is ok) and for process shared
barriers as well as all semaphores uses a ldstub lock in the padding
between the (smaller) internal structure and bigger exported type.

2006-01-03  Jakub Jelinek  <jakub@redhat.com>

	* sysdeps/unix/sysv/linux/m68k/fchownat.c: Include string.h.

	* sysdeps/sparc/sparc32/dl-machine.h (LD_SO_PRELOAD): Remove unused
	define.

	* sysdeps/sparc/sparc32/bits/atomic.h: Include stdint.h, add
	{,u}atomic*_t typedefs.
	(__sparc32_atomic_do_lock): Add __volatile and memory clobber.
	(__sparc32_atomic_do_unlock): Add memory barrier.
	(__sparc32_atomic_do_lock24, __sparc32_atomic_do_unlock24): Define.
	[!SHARED] (__v9_compare_and_exchange_val_32_acq): Define.
	(__v7_compare_and_exchange_val_acq, __v7_compare_and_exchange_bool_acq,
	__v7_exchange_acq, __v7_exchange_and_add, __v7_exchange_24_rel,
	__v7_compare_and_exchange_val_24_acq, __atomic_is_v9,
	atomic_exchange_acq, atomic_compare_and_exchange_val_24_acq,
	atomic_exchange_24_rel): Define.
	[SHARED] (atomic_exchange_and_add): Define.
	[!SHARED] (__ATOMIC_HWCAP_SPARC_V9): Define.
	[!SHARED] (_dl_hwcap): New weak decl.
	* sysdeps/sparc/sparc32/sparcv9/bits/atomic.h (atomic_exchange_24_rel,
	atomic_compare_and_exchange_val_24_acq): Define.
	* sysdeps/sparc/sparc64/bits/atomic.h (atomic_exchange_24_rel,
	atomic_compare_and_exchange_val_24_acq): Define.
nptl/
	* sysdeps/unix/sysv/linux/sparc/lowlevellock.h: Remove #error for
	sparc-linux configured glibc.
	(lll_futex_wake_unlock): Define to 1 for sparc-linux configured glibc.
	(__lll_mutex_trylock, __lll_mutex_cond_trylock, __lll_mutex_lock,
	__lll_mutex_cond_lock, __lll_mutex_timedlock): Use
	atomic_compare_and_exchange_val_24_acq instead of
	atomic_compare_and_exchange_val_acq.
	(lll_mutex_unlock, lll_mutex_unlock_force): Use atomic_exchange_24_rel
	instead of atomic_exchange_rel.
	* sysdeps/unix/sysv/linux/sparc/sparc32/lowlevellock.c: New file.
	* sysdeps/unix/sysv/linux/sparc/sparc32/pthread_barrier_init.c: New
	file.
	* sysdeps/unix/sysv/linux/sparc/sparc32/pthread_barrier_wait.c: New
	file.
	* sysdeps/unix/sysv/linux/sparc/sparc32/sem_init.c: New file.
	* sysdeps/unix/sysv/linux/sparc/sparc32/sem_post.c: New file.
	* sysdeps/unix/sysv/linux/sparc/sparc32/sem_timedwait.c: New file.
	* sysdeps/unix/sysv/linux/sparc/sparc32/sem_trywait.c: New file.
	* sysdeps/unix/sysv/linux/sparc/sparc32/sem_wait.c: New file.
	* sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/pthread_barrier_init.c:
	New file.
	* sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/pthread_barrier_wait.c:
	New file.
	* sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_init.c: New file.
	* sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_post.c: New file.
	* sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_timedwait.c: New
	file.
	* sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_trywait.c: New
	file.
	* sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_wait.c: New file.

--- libc/sysdeps/unix/sysv/linux/m68k/fchownat.c.jj	2006-01-03 11:14:23.000000000 -0500
+++ libc/sysdeps/unix/sysv/linux/m68k/fchownat.c	2006-01-03 11:14:48.000000000 -0500
@@ -20,6 +20,7 @@
 #include <fcntl.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <string.h>
 
 #include <sysdep.h>
 #include <sys/syscall.h>
--- libc/sysdeps/sparc/sparc32/bits/atomic.h.jj	2004-02-23 03:48:01.000000000 -0500
+++ libc/sysdeps/sparc/sparc32/bits/atomic.h	2006-01-03 11:21:45.000000000 -0500
@@ -1,5 +1,5 @@
 /* Atomic operations.  sparc32 version.
-   Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
 
@@ -21,6 +21,34 @@
 #ifndef _BITS_ATOMIC_H
 #define _BITS_ATOMIC_H	1
 
+#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;
+
+
 /* We have no compare and swap, just test and set.
    The following implementation contends on 64 global locks
    per library and assumes no variable will be accessed using atomic.h
@@ -41,22 +69,65 @@ volatile unsigned char __sparc32_atomic_
       unsigned int __idx = (((long) addr >> 2) ^ ((long) addr >> 12)) \
 			   & 63;				      \
       do							      \
-	__asm ("ldstub %1, %0"					      \
-	       : "=r" (__old_lock),				      \
-		 "=m" (__sparc32_atomic_locks[__idx])		      \
-	       : "m" (__sparc32_atomic_locks[__idx]));		      \
+	__asm __volatile ("ldstub %1, %0"			      \
+			  : "=r" (__old_lock),			      \
+			    "=m" (__sparc32_atomic_locks[__idx])      \
+			  : "m" (__sparc32_atomic_locks[__idx])	      \
+			  : "memory");				      \
       while (__old_lock);					      \
     }								      \
   while (0)
 
 #define __sparc32_atomic_do_unlock(addr) \
   do								      \
-    __sparc32_atomic_locks[(((long) addr >> 2)			      \
-			    ^ ((long) addr >> 12)) & 63] = 0;	      \
+    {								      \
+      __sparc32_atomic_locks[(((long) addr >> 2)		      \
+			      ^ ((long) addr >> 12)) & 63] = 0;	      \
+      __asm __volatile ("" ::: "memory");			      \
+    }								      \
+  while (0)
+
+#define __sparc32_atomic_do_lock24(addr) \
+  do								      \
+    {								      \
+      unsigned int __old_lock;					      \
+      do							      \
+	__asm __volatile ("ldstub %1, %0"			      \
+			  : "=r" (__old_lock), "=m" (*(addr))	      \
+			  : "m" (*(addr))			      \
+			  : "memory");				      \
+      while (__old_lock);					      \
+    }								      \
   while (0)
 
+#define __sparc32_atomic_do_unlock24(addr) \
+  do								      \
+    {								      \
+      *(char *) (addr) = 0;					      \
+      __asm __volatile ("" ::: "memory");			      \
+    }								      \
+  while (0)
+
+
+#ifndef SHARED
+# define __v9_compare_and_exchange_val_32_acq(mem, newval, oldval) \
+({									      \
+  register __typeof (*(mem)) __acev_tmp __asm ("%g6");			      \
+  register __typeof (mem) __acev_mem __asm ("%g1") = (mem);		      \
+  register __typeof (*(mem)) __acev_oldval __asm ("%g5");		      \
+  __acev_tmp = (newval);						      \
+  __acev_oldval = (oldval);						      \
+  /* .word 0xcde05005 is cas [%g1], %g5, %g6.  Can't use cas here though,     \
+     because as will then mark the object file as V8+ arch.  */		      \
+  __asm __volatile (".word 0xcde05005"					      \
+		    : "+r" (__acev_tmp), "=m" (*__acev_mem)		      \
+		    : "r" (__acev_oldval), "m" (*__acev_mem),		      \
+		      "r" (__acev_mem));				      \
+  __acev_tmp; })
+#endif
+
 /* The only basic operation needed is compare and exchange.  */
-#define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
+#define __v7_compare_and_exchange_val_acq(mem, newval, oldval) \
   ({ __typeof (mem) __acev_memp = (mem);			      \
      __typeof (*mem) __acev_ret;				      \
      __typeof (*mem) __acev_newval = (newval);			      \
@@ -68,7 +139,7 @@ volatile unsigned char __sparc32_atomic_
      __sparc32_atomic_do_unlock (__acev_memp);			      \
      __acev_ret; })
 
-#define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
+#define __v7_compare_and_exchange_bool_acq(mem, newval, oldval) \
   ({ __typeof (mem) __aceb_memp = (mem);			      \
      int __aceb_ret;						      \
      __typeof (*mem) __aceb_newval = (newval);			      \
@@ -82,4 +153,175 @@ volatile unsigned char __sparc32_atomic_
      __sparc32_atomic_do_unlock (__aceb_memp);			      \
      __aceb_ret; })
 
+#define __v7_exchange_acq(mem, newval) \
+  ({ __typeof (mem) __acev_memp = (mem);			      \
+     __typeof (*mem) __acev_ret;				      \
+     __typeof (*mem) __acev_newval = (newval);			      \
+								      \
+     __sparc32_atomic_do_lock (__acev_memp);			      \
+     __acev_ret = *__acev_memp;					      \
+     *__acev_memp = __acev_newval;				      \
+     __sparc32_atomic_do_unlock (__acev_memp);			      \
+     __acev_ret; })
+
+#define __v7_exchange_and_add(mem, value) \
+  ({ __typeof (mem) __acev_memp = (mem);			      \
+     __typeof (*mem) __acev_ret;				      \
+								      \
+     __sparc32_atomic_do_lock (__acev_memp);			      \
+     __acev_ret = *__acev_memp;					      \
+     *__acev_memp = __acev_ret + (value);			      \
+     __sparc32_atomic_do_unlock (__acev_memp);			      \
+     __acev_ret; })
+
+/* Special versions, which guarantee that top 8 bits of all values
+   are cleared and use those bits as the ldstub lock.  */
+#define __v7_compare_and_exchange_val_24_acq(mem, newval, oldval) \
+  ({ __typeof (mem) __acev_memp = (mem);			      \
+     __typeof (*mem) __acev_ret;				      \
+     __typeof (*mem) __acev_newval = (newval);			      \
+								      \
+     __sparc32_atomic_do_lock24 (__acev_memp);			      \
+     __acev_ret = *__acev_memp & 0xffffff;			      \
+     if (__acev_ret == (oldval))				      \
+       *__acev_memp = __acev_newval;				      \
+     else							      \
+       __sparc32_atomic_do_unlock24 (__acev_memp);		      \
+     __asm __volatile ("" ::: "memory");			      \
+     __acev_ret; })
+
+#define __v7_exchange_24_rel(mem, newval) \
+  ({ __typeof (mem) __acev_memp = (mem);			      \
+     __typeof (*mem) __acev_ret;				      \
+     __typeof (*mem) __acev_newval = (newval);			      \
+								      \
+     __sparc32_atomic_do_lock24 (__acev_memp);			      \
+     __acev_ret = *__acev_memp & 0xffffff;			      \
+     *__acev_memp = __acev_newval;				      \
+     __asm __volatile ("" ::: "memory");			      \
+     __acev_ret; })
+
+#ifdef SHARED
+
+/* When dynamically linked, we assume pre-v9 libraries are only ever
+   used on pre-v9 CPU.  */
+# define __atomic_is_v9 0
+
+# define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
+  __v7_compare_and_exchange_val_acq (mem, newval, oldval)
+
+# define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
+  __v7_compare_and_exchange_bool_acq (mem, newval, oldval)
+
+# define atomic_exchange_acq(mem, newval) \
+  __v7_exchange_acq (mem, newval)
+
+# define atomic_exchange_and_add(mem, value) \
+  __v7_exchange_and_add (mem, value)
+
+# define atomic_compare_and_exchange_val_24_acq(mem, newval, oldval) \
+  ({								      \
+     if (sizeof (*mem) != 4)					      \
+       abort ();						      \
+     __v7_compare_and_exchange_val_24_acq (mem, newval, oldval); })
+
+# define atomic_exchange_24_rel(mem, newval) \
+  ({								      \
+     if (sizeof (*mem) != 4)					      \
+       abort ();						      \
+     __v7_exchange_24_rel (mem, newval); })
+
+#else
+
+/* In libc.a/libpthread.a etc. we don't know if we'll be run on
+   pre-v9 or v9 CPU.  To be interoperable with dynamically linked
+   apps on v9 CPUs e.g. with process shared primitives, use cas insn
+   on v9 CPUs and ldstub on pre-v9.  */
+
+/* Avoid <ldsodefs.h> include here.  */
+extern uint64_t _dl_hwcap __attribute__((weak));
+# define __ATOMIC_HWCAP_SPARC_V9	16
+# define __atomic_is_v9 \
+  (__builtin_expect (&_dl_hwcap != 0, 1) \
+   && __builtin_expect (_dl_hwcap & __ATOMIC_HWCAP_SPARC_V9, \
+			__ATOMIC_HWCAP_SPARC_V9))
+
+# define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
+  ({								      \
+     __typeof (*mem) __acev_wret;				      \
+     if (sizeof (*mem) != 4)					      \
+       abort ();						      \
+     if (__atomic_is_v9)					      \
+       __acev_wret						      \
+	 = __v9_compare_and_exchange_val_32_acq (mem, newval, oldval);\
+     else							      \
+       __acev_wret						      \
+	 = __v7_compare_and_exchange_val_acq (mem, newval, oldval);   \
+     __acev_wret; })
+
+# define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
+  ({								      \
+     int __acev_wret;						      \
+     if (sizeof (*mem) != 4)					      \
+       abort ();						      \
+     if (__atomic_is_v9)					      \
+       {							      \
+	 __typeof (oldval) __acev_woldval = (oldval);		      \
+	 __acev_wret						      \
+	   = __v9_compare_and_exchange_val_32_acq (mem, newval,	      \
+						   __acev_woldval)    \
+	     != __acev_woldval;					      \
+       }							      \
+     else							      \
+       __acev_wret						      \
+	 = __v7_compare_and_exchange_bool_acq (mem, newval, oldval);  \
+     __acev_wret; })
+
+# define atomic_exchange_rel(mem, newval) \
+  ({								      \
+     __typeof (*mem) __acev_wret;				      \
+     if (sizeof (*mem) != 4)					      \
+       abort ();						      \
+     if (__atomic_is_v9)					      \
+       {							      \
+	 __typeof (mem) __acev_wmemp = (mem);			      \
+	 __typeof (*(mem)) __acev_wval = (newval);		      \
+	 do							      \
+	   __acev_wret = *__acev_wmemp;				      \
+	 while (__builtin_expect				      \
+		  (__v9_compare_and_exchange_val_32_acq (__acev_wmemp,\
+							 __acev_wval, \
+							 __acev_wret) \
+		   != __acev_wret, 0));				      \
+       }							      \
+     else							      \
+       __acev_wret = __v7_exchange_acq (mem, newval);		      \
+     __acev_wret; })
+
+# define atomic_compare_and_exchange_val_24_acq(mem, newval, oldval) \
+  ({								      \
+     __typeof (*mem) __acev_wret;				      \
+     if (sizeof (*mem) != 4)					      \
+       abort ();						      \
+     if (__atomic_is_v9)					      \
+       __acev_wret						      \
+	 = __v9_compare_and_exchange_val_32_acq (mem, newval, oldval);\
+     else							      \
+       __acev_wret						      \
+	 = __v7_compare_and_exchange_val_24_acq (mem, newval, oldval);\
+     __acev_wret; })
+
+# define atomic_exchange_24_rel(mem, newval) \
+  ({								      \
+     __typeof (*mem) __acev_w24ret;				      \
+     if (sizeof (*mem) != 4)					      \
+       abort ();						      \
+     if (__atomic_is_v9)					      \
+       __acev_w24ret = atomic_exchange_rel (mem, newval);	      \
+     else							      \
+       __acev_w24ret = __v7_exchange_24_rel (mem, newval);	      \
+     __acev_w24ret; })
+
+#endif
+
 #endif	/* bits/atomic.h */
--- libc/sysdeps/sparc/sparc32/sparcv9/bits/atomic.h.jj	2003-05-10 01:29:30.000000000 -0400
+++ libc/sysdeps/sparc/sparc32/sparcv9/bits/atomic.h	2006-01-03 10:43:20.000000000 -0500
@@ -1,5 +1,5 @@
 /* Atomic operations.  sparcv9 version.
-   Copyright (C) 2003 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
 
@@ -79,6 +79,12 @@ typedef uintmax_t uatomic_max_t;
        abort ();							      \
      __oldval; })
 
+#define atomic_compare_and_exchange_val_24_acq(mem, newval, oldval) \
+  atomic_compare_and_exchange_val_acq (mem, newval, oldval)
+
+#define atomic_exchange_24_rel(mem, newval) \
+  atomic_exchange_rel (mem, newval)
+
 #define atomic_full_barrier() \
   __asm __volatile ("membar #LoadLoad | #LoadStore"			      \
 			  " | #StoreLoad | #StoreStore" : : : "memory")
--- libc/sysdeps/sparc/sparc32/dl-machine.h.jj	2005-06-06 08:36:12.000000000 -0400
+++ libc/sysdeps/sparc/sparc32/dl-machine.h	2006-01-03 10:38:33.000000000 -0500
@@ -1,5 +1,5 @@
 /* Machine-dependent ELF dynamic relocation inline functions.  SPARC version.
-   Copyright (C) 1996-2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 1996-2003, 2004, 2005, 2006 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
@@ -40,13 +40,6 @@
 #define OPCODE_SAVE_SP	0x9de3bfa8 /* save %sp, -(16+6)*4, %sp */
 #define OPCODE_BA	0x30800000 /* b,a ?; add PC-rel word address */
 
-/* Use a different preload file when running in 32-bit emulation mode
-   on a 64-bit host.  */
-#define LD_SO_PRELOAD ((GLRO(dl_hwcap) & HWCAP_SPARC_V9) \
-		       ? "/etc/ld.so.preload32" \
-		       : "/etc/ld.so.preload")
-
-
 /* Return nonzero iff ELF header is compatible with the running host.  */
 static inline int
 elf_machine_matches_host (const Elf32_Ehdr *ehdr)
--- libc/sysdeps/sparc/sparc64/bits/atomic.h.jj	2003-05-10 01:29:30.000000000 -0400
+++ libc/sysdeps/sparc/sparc64/bits/atomic.h	2006-01-03 10:43:34.000000000 -0500
@@ -1,5 +1,5 @@
 /* Atomic operations.  sparc64 version.
-   Copyright (C) 2003 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
 
@@ -94,6 +94,12 @@ typedef uintmax_t uatomic_max_t;
        }								      \
      __oldval; })
 
+#define atomic_compare_and_exchange_val_24_acq(mem, newval, oldval) \
+  atomic_compare_and_exchange_val_acq (mem, newval, oldval)
+
+#define atomic_exchange_24_rel(mem, newval) \
+  atomic_exchange_rel (mem, newval)
+
 #define atomic_full_barrier() \
   __asm __volatile ("membar #LoadLoad | #LoadStore"			      \
 			  " | #StoreLoad | #StoreStore" : : : "memory")
--- libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/lowlevellock.c.jj	2006-01-03 10:38:33.000000000 -0500
+++ libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/lowlevellock.c	2006-01-03 10:45:06.000000000 -0500
@@ -0,0 +1,131 @@
+/* low level locking for pthread library.  SPARC version.
+   Copyright (C) 2003, 2006 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)
+{
+  do
+    {
+      int oldval = atomic_compare_and_exchange_val_24_acq (futex, 2, 1);
+      if (oldval != 0)
+	lll_futex_wait (futex, 2);
+    }
+  while (atomic_compare_and_exchange_val_24_acq (futex, 2, 0) != 0);
+}
+
+
+int
+__lll_timedlock_wait (int *futex, const struct timespec *abstime)
+{
+  /* Reject invalid timeouts.  */
+  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+    return EINVAL;
+
+  do
+    {
+      struct timeval tv;
+      struct timespec rt;
+
+      /* Get the current time.  */
+      (void) __gettimeofday (&tv, NULL);
+
+      /* Compute relative timeout.  */
+      rt.tv_sec = abstime->tv_sec - tv.tv_sec;
+      rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
+      if (rt.tv_nsec < 0)
+	{
+	  rt.tv_nsec += 1000000000;
+	  --rt.tv_sec;
+	}
+
+      /* Already timed out?  */
+      if (rt.tv_sec < 0)
+	return ETIMEDOUT;
+
+      /* Wait.  */
+      int oldval = atomic_compare_and_exchange_val_24_acq (futex, 2, 1);
+      if (oldval != 0)
+	lll_futex_timed_wait (futex, 2, &rt);
+    }
+  while (atomic_compare_and_exchange_val_24_acq (futex, 2, 0) != 0);
+
+  return 0;
+}
+
+
+/* These don't get included in libc.so  */
+#ifdef IS_IN_libpthread
+int
+lll_unlock_wake_cb (int *futex)
+{
+  int val = atomic_exchange_24_rel (futex, 0);
+
+  if (__builtin_expect (val > 1, 0))
+    lll_futex_wake (futex, 1);
+
+  return 0;
+}
+
+
+int
+__lll_timedwait_tid (int *tidp, const struct timespec *abstime)
+{
+  int tid;
+
+  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+    return EINVAL;
+
+  /* Repeat until thread terminated.  */
+  while ((tid = *tidp) != 0)
+    {
+      struct timeval tv;
+      struct timespec rt;
+
+      /* Get the current time.  */
+      (void) __gettimeofday (&tv, NULL);
+
+      /* Compute relative timeout.  */
+      rt.tv_sec = abstime->tv_sec - tv.tv_sec;
+      rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
+      if (rt.tv_nsec < 0)
+	{
+	  rt.tv_nsec += 1000000000;
+	  --rt.tv_sec;
+	}
+
+      /* Already timed out?  */
+      if (rt.tv_sec < 0)
+	return ETIMEDOUT;
+
+      /* Wait until thread terminates.  */
+      if (lll_futex_timed_wait (tidp, tid, &rt) == -ETIMEDOUT)
+	return ETIMEDOUT;
+    }
+
+  return 0;
+}
+
+#endif
--- libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pthread_barrier_init.c.jj	2006-01-03 10:38:33.000000000 -0500
+++ libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pthread_barrier_init.c	2006-01-03 12:24:16.000000000 -0500
@@ -0,0 +1,62 @@
+/* Copyright (C) 2002, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   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"
+#include <lowlevellock.h>
+
+struct sparc_pthread_barrier
+{
+  struct pthread_barrier b;
+  unsigned char left_lock;
+  unsigned char pshared;
+};
+
+int
+pthread_barrier_init (barrier, attr, count)
+     pthread_barrier_t *barrier;
+     const pthread_barrierattr_t *attr;
+     unsigned int count;
+{
+  struct sparc_pthread_barrier *ibarrier;
+
+  if (__builtin_expect (count == 0, 0))
+    return EINVAL;
+
+  struct pthread_barrierattr *iattr = (struct pthread_barrierattr *) attr;
+  if (iattr != NULL)
+    {
+      if (iattr->pshared != PTHREAD_PROCESS_PRIVATE
+	  && __builtin_expect (iattr->pshared != PTHREAD_PROCESS_SHARED, 0))
+	/* Invalid attribute.  */
+	return EINVAL;
+    }
+
+  ibarrier = (struct sparc_pthread_barrier *) barrier;
+
+  /* Initialize the individual fields.  */
+  ibarrier->b.lock = LLL_LOCK_INITIALIZER;
+  ibarrier->b.left = count;
+  ibarrier->b.init_count = count;
+  ibarrier->b.curr_event = 0;
+  ibarrier->left_lock = 0;
+  ibarrier->pshared = (iattr && iattr->pshared == PTHREAD_PROCESS_SHARED);
+
+  return 0;
+}
--- libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/pthread_barrier_init.c.jj	2006-01-03 10:38:33.000000000 -0500
+++ libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/pthread_barrier_init.c	2006-01-03 10:38:33.000000000 -0500
@@ -0,0 +1 @@
+#include "../../../../../../../pthread_barrier_init.c"
--- libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/pthread_barrier_wait.c.jj	2006-01-03 10:38:33.000000000 -0500
+++ libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/pthread_barrier_wait.c	2006-01-03 10:38:33.000000000 -0500
@@ -0,0 +1 @@
+#include "../../../../../../pthread/pthread_barrier_wait.c"
--- libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_init.c.jj	2006-01-03 10:38:33.000000000 -0500
+++ libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_init.c	2006-01-03 10:38:33.000000000 -0500
@@ -0,0 +1 @@
+#include "../../../../../../../sem_init.c"
--- libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_post.c.jj	2006-01-03 10:38:33.000000000 -0500
+++ libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_post.c	2006-01-03 10:38:33.000000000 -0500
@@ -0,0 +1 @@
+#include "../../../sem_post.c"
--- libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_timedwait.c.jj	2006-01-03 10:38:33.000000000 -0500
+++ libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_timedwait.c	2006-01-03 10:38:33.000000000 -0500
@@ -0,0 +1 @@
+#include "../../../sem_timedwait.c"
--- libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_trywait.c.jj	2006-01-03 10:38:33.000000000 -0500
+++ libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_trywait.c	2006-01-03 10:38:33.000000000 -0500
@@ -0,0 +1 @@
+#include "../../../sem_trywait.c"
--- libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_wait.c.jj	2006-01-03 10:38:33.000000000 -0500
+++ libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_wait.c	2006-01-03 10:38:33.000000000 -0500
@@ -0,0 +1 @@
+#include "../../../sem_wait.c"
--- libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pthread_barrier_wait.c.jj	2006-01-03 10:38:33.000000000 -0500
+++ libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pthread_barrier_wait.c	2006-01-03 11:22:23.000000000 -0500
@@ -0,0 +1,100 @@
+/* Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Martin Schwidefsky <schwidefsky@de.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 <pthreadP.h>
+
+struct sparc_pthread_barrier
+{
+  struct pthread_barrier b;
+  unsigned char left_lock;
+  unsigned char pshared;
+};
+
+/* Wait on barrier.  */
+int
+pthread_barrier_wait (barrier)
+     pthread_barrier_t *barrier;
+{
+  struct sparc_pthread_barrier *ibarrier
+    = (struct sparc_pthread_barrier *) barrier;
+  int result = 0;
+
+  /* Make sure we are alone.  */
+  lll_lock (ibarrier->b.lock);
+
+  /* One more arrival.  */
+  --ibarrier->b.left;
+
+  /* Are these all?  */
+  if (ibarrier->b.left == 0)
+    {
+      /* Yes. Increment the event counter to avoid invalid wake-ups and
+	 tell the current waiters that it is their turn.  */
+      ++ibarrier->b.curr_event;
+
+      /* Wake up everybody.  */
+      lll_futex_wake (&ibarrier->b.curr_event, INT_MAX);
+
+      /* This is the thread which finished the serialization.  */
+      result = PTHREAD_BARRIER_SERIAL_THREAD;
+    }
+  else
+    {
+      /* The number of the event we are waiting for.  The barrier's event
+	 number must be bumped before we continue.  */
+      unsigned int event = ibarrier->b.curr_event;
+
+      /* Before suspending, make the barrier available to others.  */
+      lll_unlock (ibarrier->b.lock);
+
+      /* Wait for the event counter of the barrier to change.  */
+      do
+	lll_futex_wait (&ibarrier->b.curr_event, event);
+      while (event == ibarrier->b.curr_event);
+    }
+
+  /* Make sure the init_count is stored locally or in a register.  */
+  unsigned int init_count = ibarrier->b.init_count;
+
+  /* If this was the last woken thread, unlock.  */
+  if (__atomic_is_v9 || ibarrier->pshared == 0)
+    {
+      if (atomic_increment_val (&ibarrier->b.left) == init_count)
+	/* We are done.  */
+	lll_unlock (ibarrier->b.lock);
+    }
+  else
+    {
+      unsigned int left;
+      /* Slightly more complicated.  On pre-v9 CPUs, atomic_increment_val
+	 is only atomic for threads within the same process, not for
+	 multiple processes.  */
+      __sparc32_atomic_do_lock24 (&ibarrier->left_lock);
+      left = ++ibarrier->b.left;
+      __sparc32_atomic_do_unlock24 (&ibarrier->left_lock);
+      if (left == init_count)
+        /* We are done.  */
+        lll_unlock (ibarrier->b.lock);
+    }
+
+  return result;
+}
--- libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_init.c.jj	2006-01-03 10:38:33.000000000 -0500
+++ libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_init.c	2006-01-03 10:38:33.000000000 -0500
@@ -0,0 +1,63 @@
+/* Copyright (C) 2002, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   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 <semaphore.h>
+#include <lowlevellock.h>
+#include <shlib-compat.h>
+#include "semaphoreP.h"
+
+struct sparc_sem
+{
+  struct sem s;
+  unsigned char lock;
+};
+
+
+int
+__new_sem_init (sem, pshared, value)
+     sem_t *sem;
+     int pshared;
+     unsigned int value;
+{
+  /* Parameter sanity check.  */
+  if (__builtin_expect (value > SEM_VALUE_MAX, 0))
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  /* Map to the internal type.  */
+  struct sparc_sem *isem = (struct sparc_sem *) sem;
+
+  /* Use the value the user provided.  */
+  isem->s.count = value;
+
+  isem->lock = 0;
+
+  /* We can completely ignore the PSHARED parameter since inter-process
+     use needs no special preparation.  */
+
+  return 0;
+}
+versioned_symbol (libpthread, __new_sem_init, sem_init, GLIBC_2_1);
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
+strong_alias (__new_sem_init, __old_sem_init)
+compat_symbol (libpthread, __old_sem_init, sem_init, GLIBC_2_0);
+#endif
--- libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_post.c.jj	2006-01-03 10:38:33.000000000 -0500
+++ libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_post.c	2006-01-03 10:38:33.000000000 -0500
@@ -0,0 +1,54 @@
+/* sem_post -- post to a POSIX semaphore.  SPARC version.
+   Copyright (C) 2003, 2004, 2006 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 <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, nr;
+
+  if (__atomic_is_v9)
+    nr = atomic_increment_val (futex);
+  else
+    {
+      __sparc32_atomic_do_lock24 (futex + 1);
+      nr = ++*futex;
+      __sparc32_atomic_do_unlock24 (futex + 1);
+    }
+  int err = lll_futex_wake (futex, nr);
+  if (__builtin_expect (err, 0) < 0)
+    {
+      __set_errno (-err);
+      return -1;
+    }
+  return 0;
+}
+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
--- libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_timedwait.c.jj	2006-01-03 10:38:33.000000000 -0500
+++ libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_timedwait.c	2006-01-03 10:38:33.000000000 -0500
@@ -0,0 +1,117 @@
+/* sem_timedwait -- wait on a semaphore.  SPARC version.
+   Copyright (C) 2003, 2006 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 <pthreadP.h>
+#include <shlib-compat.h>
+
+
+int
+sem_timedwait (sem_t *sem, const struct timespec *abstime)
+{
+  /* First check for cancellation.  */
+  CANCELLATION_P (THREAD_SELF);
+
+  int *futex = (int *) sem;
+  int val;
+  int err;
+
+  if (*futex > 0)
+    {
+      if (__atomic_is_v9)
+	val = atomic_decrement_if_positive (futex);
+      else
+	{
+	  __sparc32_atomic_do_lock24 (futex + 1);
+	  val = *futex;
+	  if (val > 0)
+	    *futex = val - 1;
+	  __sparc32_atomic_do_unlock24 (futex + 1);
+	}
+      if (val > 0)
+	return 0;
+    }
+
+  err = -EINVAL;
+  if (abstime->tv_nsec < 0 || 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;
+
+      /* Enable asynchronous cancellation.  Required by the standard.  */
+      int oldtype = __pthread_enable_asynccancel ();
+
+      err = lll_futex_timed_wait (futex, 0, &rt);
+
+      /* Disable asynchronous cancellation.  */
+      __pthread_disable_asynccancel (oldtype);
+
+      if (err != 0 && err != -EWOULDBLOCK)
+	goto error_return;
+
+      if (__atomic_is_v9)
+	val = atomic_decrement_if_positive (futex);
+      else
+	{
+	  __sparc32_atomic_do_lock24 (futex + 1);
+	  val = *futex;
+	  if (val > 0)
+	    *futex = val - 1;
+	  __sparc32_atomic_do_unlock24 (futex + 1);
+	}
+    }
+  while (val <= 0);
+
+  return 0;
+
+ error_return:
+  __set_errno (-err);
+  return -1;
+}
--- libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_trywait.c.jj	2006-01-03 10:38:33.000000000 -0500
+++ libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_trywait.c	2006-01-03 11:11:40.000000000 -0500
@@ -0,0 +1,59 @@
+/* sem_trywait -- wait on a semaphore.  SPARC version.
+   Copyright (C) 2003, 2006 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)
+    {
+      if (__atomic_is_v9)
+	val = atomic_decrement_if_positive (futex);
+      else
+	{
+	  __sparc32_atomic_do_lock24 (futex + 1);
+	  val = *futex;
+	  if (val > 0)
+	    *futex = val - 1;
+	  __sparc32_atomic_do_unlock24 (futex + 1);
+	}
+      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
--- libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_wait.c.jj	2006-01-03 10:38:33.000000000 -0500
+++ libc/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_wait.c	2006-01-03 11:12:05.000000000 -0500
@@ -0,0 +1,74 @@
+/* sem_wait -- wait on a semaphore.  SPARC version.
+   Copyright (C) 2003, 2006 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 <pthreadP.h>
+#include <shlib-compat.h>
+
+
+int
+__new_sem_wait (sem_t *sem)
+{
+  /* First check for cancellation.  */
+  CANCELLATION_P (THREAD_SELF);
+
+  int *futex = (int *) sem;
+  int err;
+
+  do
+    {
+      int val;
+      if (__atomic_is_v9)
+	val = atomic_decrement_if_positive (futex);
+      else
+	{
+	  __sparc32_atomic_do_lock24 (futex + 1);
+	  val = *futex;
+	  if (val > 0)
+	    *futex = val - 1;
+	  __sparc32_atomic_do_unlock24 (futex + 1);
+	}
+      if (val > 0)
+	return 0;
+
+      /* Enable asynchronous cancellation.  Required by the standard.  */
+      int oldtype = __pthread_enable_asynccancel ();
+
+      err = lll_futex_wait (futex, 0);
+
+      /* Disable asynchronous cancellation.  */
+      __pthread_disable_asynccancel (oldtype);
+    }
+  while (err == 0 || err == -EWOULDBLOCK);
+
+  __set_errno (-err);
+  return -1;
+}
+
+versioned_symbol (libpthread, __new_sem_wait, sem_wait, GLIBC_2_1);
+#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_1)
+strong_alias (__new_sem_wait, __old_sem_wait)
+compat_symbol (libpthread, __old_sem_wait, sem_wait, GLIBC_2_0);
+#endif
--- libc/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.h.jj	2005-09-09 06:58:42.000000000 -0400
+++ libc/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.h	2006-01-03 10:44:48.000000000 -0500
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
 
@@ -79,7 +79,11 @@
   })
 
 /* Returns non-zero if error happened, zero if success.  */
-#define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2) \
+#ifdef __sparc32_atomic_do_lock
+/* Avoid FUTEX_WAKE_OP if supporting pre-v9 CPUs.  */
+# define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2) 1
+#else
+# define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2) \
   ({									      \
     INTERNAL_SYSCALL_DECL (__err);					      \
     long int __ret;							      \
@@ -90,16 +94,13 @@
 			      FUTEX_OP_CLEAR_WAKE_IF_GT_ONE);		      \
     INTERNAL_SYSCALL_ERROR_P (__ret, __err);				      \
   })
-
-#ifdef __sparc32_atomic_do_lock
-#error SPARC < v9 does not support compare and swap which is essential for futex based locking
 #endif
 
 static inline int
 __attribute__ ((always_inline))
 __lll_mutex_trylock (int *futex)
 {
-  return atomic_compare_and_exchange_val_acq (futex, 1, 0) != 0;
+  return atomic_compare_and_exchange_val_24_acq (futex, 1, 0) != 0;
 }
 #define lll_mutex_trylock(futex) __lll_mutex_trylock (&(futex))
 
@@ -107,7 +108,7 @@ static inline int
 __attribute__ ((always_inline))
 __lll_mutex_cond_trylock (int *futex)
 {
-  return atomic_compare_and_exchange_val_acq (futex, 2, 0) != 0;
+  return atomic_compare_and_exchange_val_24_acq (futex, 2, 0) != 0;
 }
 #define lll_mutex_cond_trylock(futex) __lll_mutex_cond_trylock (&(futex))
 
@@ -119,7 +120,7 @@ static inline void
 __attribute__ ((always_inline))
 __lll_mutex_lock (int *futex)
 {
-  int val = atomic_compare_and_exchange_val_acq (futex, 1, 0);
+  int val = atomic_compare_and_exchange_val_24_acq (futex, 1, 0);
 
   if (__builtin_expect (val != 0, 0))
     __lll_lock_wait (futex);
@@ -131,7 +132,7 @@ static inline void
 __attribute__ ((always_inline))
 __lll_mutex_cond_lock (int *futex)
 {
-  int val = atomic_compare_and_exchange_val_acq (futex, 2, 0);
+  int val = atomic_compare_and_exchange_val_24_acq (futex, 2, 0);
 
   if (__builtin_expect (val != 0, 0))
     __lll_lock_wait (futex);
@@ -147,7 +148,7 @@ static inline int
 __attribute__ ((always_inline))
 __lll_mutex_timedlock (int *futex, const struct timespec *abstime)
 {
-  int val = atomic_compare_and_exchange_val_acq (futex, 1, 0);
+  int val = atomic_compare_and_exchange_val_24_acq (futex, 1, 0);
   int result = 0;
 
   if (__builtin_expect (val != 0, 0))
@@ -160,7 +161,7 @@ __lll_mutex_timedlock (int *futex, const
 #define lll_mutex_unlock(lock) \
   ((void) ({								      \
     int *__futex = &(lock);						      \
-    int __val = atomic_exchange_rel (__futex, 0);			      \
+    int __val = atomic_exchange_24_rel (__futex, 0);			      \
     if (__builtin_expect (__val > 1, 0))				      \
       lll_futex_wake (__futex, 1);					      \
   }))
@@ -168,7 +169,7 @@ __lll_mutex_timedlock (int *futex, const
 #define lll_mutex_unlock_force(lock) \
   ((void) ({								      \
     int *__futex = &(lock);						      \
-    (void) atomic_exchange_rel (__futex, 0);				      \
+    (void) atomic_exchange_24_rel (__futex, 0);				      \
     lll_futex_wake (__futex, 1);					      \
   }))
 

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]