about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--nptl/ChangeLog29
-rw-r--r--nptl/Makefile2
-rw-r--r--nptl/sem_getvalue.c6
-rw-r--r--nptl/sem_init.c47
-rw-r--r--nptl/sem_open.c12
-rw-r--r--nptl/semaphoreP.h4
-rw-r--r--nptl/sysdeps/unix/sysv/linux/Makefile5
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i486/sem_post.S18
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S230
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i486/sem_wait.S284
-rw-r--r--nptl/sysdeps/unix/sysv/linux/internaltypes.h13
-rw-r--r--nptl/sysdeps/unix/sysv/linux/sem_post.c30
-rw-r--r--nptl/sysdeps/unix/sysv/linux/sem_timedwait.c68
-rw-r--r--nptl/sysdeps/unix/sysv/linux/sem_wait.c60
-rw-r--r--nptl/sysdeps/unix/sysv/linux/structsem.sym10
-rw-r--r--nptl/sysdeps/unix/sysv/linux/x86_64/sem_post.S17
-rw-r--r--nptl/sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S223
-rw-r--r--nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S222
-rw-r--r--nptl/tst-typesizes.c5
19 files changed, 1088 insertions, 197 deletions
diff --git a/nptl/ChangeLog b/nptl/ChangeLog
index 923364cae5..4778511191 100644
--- a/nptl/ChangeLog
+++ b/nptl/ChangeLog
@@ -1,4 +1,33 @@
 2007-05-25  Ulrich Drepper  <drepper@redhat.com>
+
+	* semaphoreP.h: Declare __old_sem_init and __old_sem_wait.
+	* sem_init.c (__new_sem_init): Rewrite to initialize all three
+	fields in the structure.
+	(__old_sem_init): New function.
+	* sem_open.c: Initialize all fields of the structure.
+	* sem_getvalue.c: Adjust for renamed element.
+	* sysdeps/unix/sysv/linux/Makefile [subdir=nptl]
+	(gen-as-const-headers): Add structsem.sym.
+	* sysdeps/unix/sysv/linux/structsem.sym: New file.
+	* sysdeps/unix/sysv/linux/internaltypes.h: Rename struct sem to
+	struct new_sem.  Add struct old_sem.
+	* sysdeps/unix/sysv/linux/sem_post.c: Wake only when there are waiters.
+	* sysdeps/unix/sysv/linux/i386/i486/sem_post.S: Likewise.
+	* sysdeps/unix/sysv/linux/x86_64/sem_post.S: Likewise.
+	* sysdeps/unix/sysv/linux/sem_wait.c: Indicate that there are waiters.
+	* sysdeps/unix/sysv/linux/i386/i486/sem_wait.S: Likewise.
+	* sysdeps/unix/sysv/linux/x86_64/sem_wait.S: Likewise.
+	* sysdeps/unix/sysv/linux/sem_timedwait.c: Likewise.
+	* sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S: Likewise.
+	* sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S: Likewise.
+	* Makefile (tests): Add tst-sem10, tst-sem11, tst-sem12.
+	* tst-sem10.c: New file.
+	* tst-sem11.c: New file.
+	* tst-sem12.c: New file.
+	* tst-typesizes.c: Test struct new_sem and struct old_sem instead
+	of struct sem.
+
+2007-05-25  Ulrich Drepper  <drepper@redhat.com>
 	    Jakub Jelinek  <jakub@redhat.com>
 
 	* sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S (sem_timedwait):
diff --git a/nptl/Makefile b/nptl/Makefile
index 42f2fe699f..a9eac89e41 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -218,7 +218,7 @@ tests = tst-typesizes \
 	tst-once1 tst-once2 tst-once3 tst-once4 \
 	tst-key1 tst-key2 tst-key3 tst-key4 \
 	tst-sem1 tst-sem2 tst-sem3 tst-sem4 tst-sem5 tst-sem6 tst-sem7 \
-	tst-sem8 tst-sem9 \
+	tst-sem8 tst-sem9 tst-sem10 tst-sem11 tst-sem12 \
 	tst-barrier1 tst-barrier2 tst-barrier3 tst-barrier4 \
 	tst-align tst-align2 tst-align3 \
 	tst-basic1 tst-basic2 tst-basic3 tst-basic4 tst-basic5 tst-basic6 \
diff --git a/nptl/sem_getvalue.c b/nptl/sem_getvalue.c
index 6bc7ea82b4..3b17e59629 100644
--- a/nptl/sem_getvalue.c
+++ b/nptl/sem_getvalue.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -27,11 +27,11 @@ __new_sem_getvalue (sem, sval)
      sem_t *sem;
      int *sval;
 {
-  struct sem *isem = (struct sem *) sem;
+  struct new_sem *isem = (struct new_sem *) sem;
 
   /* XXX Check for valid SEM parameter.  */
 
-  *sval = isem->count;
+  *sval = isem->value;
 
   return 0;
 }
diff --git a/nptl/sem_init.c b/nptl/sem_init.c
index 8709911ac3..e29d900588 100644
--- a/nptl/sem_init.c
+++ b/nptl/sem_init.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -22,6 +22,7 @@
 #include <lowlevellock.h>
 #include <shlib-compat.h>
 #include "semaphoreP.h"
+#include <kernel-features.h>
 
 
 int
@@ -38,18 +39,50 @@ __new_sem_init (sem, pshared, value)
     }
 
   /* Map to the internal type.  */
-  struct sem *isem = (struct sem *) sem;
+  struct new_sem *isem = (struct new_sem *) sem;
 
-  /* Use the value the user provided.  */
-  isem->count = value;
+  /* Use the values the user provided.  */
+  isem->value = value;
+#ifdef __ASSUME_PRIVATE_FUTEX
+  isem->private = pshared ? 0 : FUTEX_PRIVATE_FLAG;
+#else
+  isem->private = pshared ? 0 : THREAD_GETMEM (THREAD_SELF,
+					       header.private_futex);
+#endif
 
-  /* We can completely ignore the PSHARED parameter since inter-process
-     use needs no special preparation.  */
+  isem->nwaiters = 0;
 
   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)
+int
+attribute_compat_text_section
+__old_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 old_sem *isem = (struct old_sem *) sem;
+
+  /* Use the value the user provided.  */
+  isem->value = value;
+
+  /* We cannot store the PSHARED attribute.  So we always use the
+     operations needed for shared semaphores.  */
+
+  return 0;
+}
 compat_symbol (libpthread, __old_sem_init, sem_init, GLIBC_2_0);
 #endif
diff --git a/nptl/sem_open.c b/nptl/sem_open.c
index 66bcb13aec..27d308e920 100644
--- a/nptl/sem_open.c
+++ b/nptl/sem_open.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2006 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2006, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -304,12 +304,14 @@ sem_open (const char *name, int oflag, ...)
       /* Create the initial file content.  */
       sem_t initsem;
 
-      struct sem *iinitsem = (struct sem *) &initsem;
-      iinitsem->count = value;
+      struct new_sem *iinitsem = (struct new_sem *) &initsem;
+      iinitsem->value = value;
+      iinitsem->private = 0;
+      iinitsem->nwaiters = 0;
 
       /* Initialize the remaining bytes as well.  */
-      memset ((char *) &initsem + sizeof (struct sem), '\0',
-	      sizeof (sem_t) - sizeof (struct sem));
+      memset ((char *) &initsem + sizeof (struct new_sem), '\0',
+	      sizeof (sem_t) - sizeof (struct new_sem));
 
       tmpfname = (char *) alloca (mountpoint.dirlen + 6 + 1);
       char *xxxxxx = __mempcpy (tmpfname, mountpoint.dir, mountpoint.dirlen);
diff --git a/nptl/semaphoreP.h b/nptl/semaphoreP.h
index 754609a1a8..9659059900 100644
--- a/nptl/semaphoreP.h
+++ b/nptl/semaphoreP.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2006 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2006, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -60,8 +60,10 @@ extern int __sem_search (const void *a, const void *b) attribute_hidden;
 
 /* Prototypes of functions with multiple interfaces.  */
 extern int __new_sem_init (sem_t *sem, int pshared, unsigned int value);
+extern int __old_sem_init (sem_t *sem, int pshared, unsigned int value);
 extern int __new_sem_destroy (sem_t *sem);
 extern int __new_sem_post (sem_t *sem);
 extern int __new_sem_wait (sem_t *sem);
+extern int __old_sem_wait (sem_t *sem);
 extern int __new_sem_trywait (sem_t *sem);
 extern int __new_sem_getvalue (sem_t *sem, int *sval);
diff --git a/nptl/sysdeps/unix/sysv/linux/Makefile b/nptl/sysdeps/unix/sysv/linux/Makefile
index cfcdb6d97f..ad5ae6ad12 100644
--- a/nptl/sysdeps/unix/sysv/linux/Makefile
+++ b/nptl/sysdeps/unix/sysv/linux/Makefile
@@ -1,4 +1,4 @@
-# Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+# Copyright (C) 2002,2003,2004,2005,2006,2007 Free Software Foundation, Inc.
 # This file is part of the GNU C Library.
 # Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -25,7 +25,8 @@ libpthread-sysdep_routines += pt-fork pthread_mutex_cond_lock
 
 gen-as-const-headers += lowlevelcond.sym lowlevelrwlock.sym \
 			lowlevelbarrier.sym unwindbuf.sym \
-			lowlevelrobustlock.sym pthread-pi-defines.sym
+			lowlevelrobustlock.sym pthread-pi-defines.sym \
+			structsem.sym
 endif
 
 ifeq ($(subdir),posix)
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_post.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_post.S
index 71e96d2228..e66db146ec 100644
--- a/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_post.S
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_post.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2005, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -20,6 +20,7 @@
 #include <sysdep.h>
 #include <shlib-compat.h>
 #include <pthread-errnos.h>
+#include <structsem.h>
 
 #ifndef UP
 # define LOCK lock
@@ -40,19 +41,26 @@ __new_sem_post:
 	pushl	%ebx
 
 	movl	8(%esp), %ebx
-	movl	$1, %edx
+
 	LOCK
-	xaddl	%edx, (%ebx)
+#if VALUE == 0
+	addl	$1, (%ebx)
+#else
+	addl	$1, VALUE(%ebx)
+#endif
+
+	cmpl	$0, NWAITERS(%ebx)
+	je	2f
 
 	movl	$SYS_futex, %eax
 	movl	$FUTEX_WAKE, %ecx
-	addl	$1, %edx
+	movl	$1, %edx
 	ENTER_KERNEL
 
 	testl	%eax, %eax
 	js	1f
 
-	xorl	%eax, %eax
+2:	xorl	%eax, %eax
 	popl	%ebx
 	ret
 
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S
index bf70e17fca..3677ab3bf9 100644
--- a/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S
@@ -20,6 +20,7 @@
 #include <sysdep.h>
 #include <shlib-compat.h>
 #include <pthread-errnos.h>
+#include <structsem.h>
 
 #ifndef UP
 # define LOCK lock
@@ -32,19 +33,18 @@
 #define FUTEX_WAKE		1
 
 
+#if VALUE != 0
+# error "code needs to be rewritten for VALUE != 0"
+#endif
+
+
 	.text
 
 	.globl	sem_timedwait
 	.type	sem_timedwait,@function
 	.align	16
-	cfi_startproc
 sem_timedwait:
-	/* First check for cancellation.  */
-	movl	%gs:CANCELHANDLING, %eax
-	andl	$0xfffffff9, %eax
-	cmpl	$8, %eax
-	je	10f
-
+.LSTARTCODE:
 	movl	4(%esp), %ecx
 
 	movl	(%ecx), %eax
@@ -61,24 +61,24 @@ sem_timedwait:
 
 	/* Check whether the timeout value is valid.  */
 1:	pushl	%esi
-	cfi_adjust_cfa_offset(4)
+.Lpush_esi:
 	pushl	%edi
-	cfi_adjust_cfa_offset(4)
+.Lpush_edi:
 	pushl	%ebx
-	cfi_adjust_cfa_offset(4)
+.Lpush_ebx:
 	subl	$12, %esp
-	cfi_adjust_cfa_offset(12)
+.Lsub_esp:
 
 	movl	32(%esp), %edi
-	cfi_offset(7, -12)		/* %edi */
 
 	/* Check for invalid nanosecond field.  */
 	cmpl	$1000000000, 4(%edi)
 	movl	$EINVAL, %esi
-	cfi_offset(6, -8)		/* %esi */
 	jae	6f
 
-	cfi_offset(3, -16)		/* %ebx */
+	LOCK
+	incl	NWAITERS(%ecx)
+
 7:	xorl	%ecx, %ecx
 	movl	%esp, %ebx
 	movl	%ecx, %edx
@@ -103,10 +103,11 @@ sem_timedwait:
 	movl	%ecx, (%esp)	/* Store relative timeout.  */
 	movl	%edx, 4(%esp)
 
+.LcleanupSTART:
 	call	__pthread_enable_asynccancel
 	movl	%eax, 8(%esp)
 
-	movl	28(%esp), %ebx
+	movl	28(%esp), %ebx	/* Load semaphore address.  */
 	xorl	%ecx, %ecx
 	movl	%esp, %esi
 	movl	$SYS_futex, %eax
@@ -116,6 +117,7 @@ sem_timedwait:
 
 	movl	8(%esp), %eax
 	call	__pthread_disable_asynccancel
+.LcleanupEND:
 
 	testl	%esi, %esi
 	je	9f
@@ -131,24 +133,22 @@ sem_timedwait:
 	cmpxchgl %ecx, (%ebx)
 	jne	8b
 
-	addl	$12, %esp
-	cfi_adjust_cfa_offset(-12)
 	xorl	%eax, %eax
+
+10:	LOCK
+	decl	NWAITERS(%ebx)
+
+	addl	$12, %esp
+.Ladd_esp:
 	popl	%ebx
-	cfi_adjust_cfa_offset(-4)
-	cfi_restore(3)
+.Lpop_ebx:
 	popl	%edi
-	cfi_adjust_cfa_offset(-4)
-	cfi_restore(7)
+.Lpop_edi:
 	popl	%esi
-	cfi_adjust_cfa_offset(-4)
-	cfi_restore(6)
+.Lpop_esi:
 	ret
 
-	cfi_adjust_cfa_offset(24)
-	cfi_offset(6, -8)		/* %esi */
-	cfi_offset(7, -12)	 	/* %edi */
-	cfi_offset(3, -16)		/* %ebx */
+.Lafter_ret:
 3:	negl	%esi
 6:
 #ifdef PIC
@@ -172,25 +172,163 @@ sem_timedwait:
 	movl	%esi, (%eax)
 #endif
 
-	addl	$12, %esp
-	cfi_adjust_cfa_offset(-12)
+	movl	28(%esp), %ebx	/* Load semaphore address.  */
 	orl	$-1, %eax
-	popl	%ebx
-	cfi_adjust_cfa_offset(-4)
-	cfi_restore(3)
-	popl	%edi
-	cfi_adjust_cfa_offset(-4)
-	cfi_restore(7)
-	popl	%esi
-	cfi_adjust_cfa_offset(-4)
-	cfi_restore(6)
-	ret
+	jmp	10b
+	.size	sem_timedwait,.-sem_timedwait
 
-10:	/* Canceled.  */
-	movl	$0xffffffff, %gs:RESULT
+
+	.type	sem_wait_cleanup,@function
+sem_wait_cleanup:
 	LOCK
-	orl	$0x10, %gs:CANCELHANDLING
-	movl	%gs:CLEANUP_JMP_BUF, %eax
-	jmp	HIDDEN_JUMPTARGET (__pthread_unwind)
-	cfi_endproc
-	.size	sem_timedwait,.-sem_timedwait
+	decl	NWAITERS(%ebx)
+	movl	%eax, (%esp)
+.LcallUR:
+	call	_Unwind_Resume@PLT
+	hlt
+.LENDCODE:
+	.size	sem_wait_cleanup,.-sem_wait_cleanup
+
+
+	.section .gcc_except_table,"a",@progbits
+.LexceptSTART:
+	.byte	0xff				# @LPStart format (omit)
+	.byte	0xff				# @TType format (omit)
+	.byte	0x01				# call-site format
+						# DW_EH_PE_uleb128
+	.uleb128 .Lcstend-.Lcstbegin
+.Lcstbegin:
+	.uleb128 .LcleanupSTART-.LSTARTCODE
+	.uleb128 .LcleanupEND-.LcleanupSTART
+	.uleb128 sem_wait_cleanup-.LSTARTCODE
+	.uleb128  0
+	.uleb128 .LcallUR-.LSTARTCODE
+	.uleb128 .LENDCODE-.LcallUR
+	.uleb128 0
+	.uleb128  0
+.Lcstend:
+
+
+	.section .eh_frame,"a",@progbits
+.LSTARTFRAME:
+	.long	.LENDCIE-.LSTARTCIE		# Length of the CIE.
+.LSTARTCIE:
+	.long	0				# CIE ID.
+	.byte	1				# Version number.
+#ifdef SHARED
+	.string	"zPLR"				# NUL-terminated augmentation
+						# string.
+#else
+	.string	"zPL"				# NUL-terminated augmentation
+						# string.
+#endif
+	.uleb128 1				# Code alignment factor.
+	.sleb128 -4				# Data alignment factor.
+	.byte	8				# Return address register
+						# column.
+#ifdef SHARED
+	.uleb128 7				# Augmentation value length.
+	.byte	0x9b				# Personality: DW_EH_PE_pcrel
+						# + DW_EH_PE_sdata4
+						# + DW_EH_PE_indirect
+	.long	DW.ref.__gcc_personality_v0-.
+	.byte	0x1b				# LSDA Encoding: DW_EH_PE_pcrel
+						# + DW_EH_PE_sdata4.
+	.byte	0x1b				# FDE Encoding: DW_EH_PE_pcrel
+						# + DW_EH_PE_sdata4.
+#else
+	.uleb128 6				# Augmentation value length.
+	.byte	0x0				# Personality: absolute
+	.long	__gcc_personality_v0
+	.byte	0x0				# LSDA Encoding: absolute
+#endif
+	.byte 0x0c				# DW_CFA_def_cfa
+	.uleb128 4
+	.uleb128 4
+	.byte	0x88				# DW_CFA_offset, column 0x10
+	.uleb128 1
+	.align 4
+.LENDCIE:
+
+	.long	.LENDFDE-.LSTARTFDE		# Length of the FDE.
+.LSTARTFDE:
+	.long	.LSTARTFDE-.LSTARTFRAME		# CIE pointer.
+#ifdef SHARED
+	.long	.LSTARTCODE-.			# PC-relative start address
+						# of the code.
+#else
+	.long	.LSTARTCODE			# Start address of the code.
+#endif
+	.long	.LENDCODE-.LSTARTCODE		# Length of the code.
+	.uleb128 4				# Augmentation size
+#ifdef SHARED
+	.long	.LexceptSTART-.
+#else
+	.long	.LexceptSTART
+#endif
+
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Lpush_esi-.LSTARTCODE
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 8
+	.byte   0x86				# DW_CFA_offset %esi
+        .uleb128 2
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Lpush_edi-.Lpush_esi
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 12
+	.byte   0x87				# DW_CFA_offset %edi
+        .uleb128 3
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Lpush_ebx-.Lpush_edi
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 16
+	.byte   0x83				# DW_CFA_offset %ebx
+        .uleb128 4
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Lsub_esp-.Lpush_ebx
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 28
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Ladd_esp-.Lsub_esp
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 16
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Lpop_ebx-.Ladd_esp
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 12
+	.byte	0xc3				# DW_CFA_restore %ebx
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Lpop_edi-.Lpop_ebx
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 8
+	.byte	0xc7				# DW_CFA_restore %edi
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Lpop_esi-.Lpop_edi
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 4
+	.byte	0xc6				# DW_CFA_restore %esi
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Lafter_ret-.Lpop_esi
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 28
+	.byte   0x86				# DW_CFA_offset %esi
+        .uleb128 2
+	.byte   0x87				# DW_CFA_offset %edi
+        .uleb128 3
+	.byte   0x83				# DW_CFA_offset %ebx
+        .uleb128 4
+	.align	4
+.LENDFDE:
+
+
+#ifdef SHARED
+	.hidden	DW.ref.__gcc_personality_v0
+	.weak	DW.ref.__gcc_personality_v0
+	.section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
+	.align	4
+	.type	DW.ref.__gcc_personality_v0, @object
+	.size	DW.ref.__gcc_personality_v0, 4
+DW.ref.__gcc_personality_v0:
+	.long	__gcc_personality_v0
+#endif
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_wait.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_wait.S
index b1296275d0..bb4d6443e9 100644
--- a/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_wait.S
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_wait.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2005, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -20,6 +20,7 @@
 #include <sysdep.h>
 #include <shlib-compat.h>
 #include <pthread-errnos.h>
+#include <structsem.h>
 
 #ifndef UP
 # define LOCK lock
@@ -31,19 +32,253 @@
 #define FUTEX_WAKE		1
 
 
+#if VALUE != 0
+# error "code needs to be rewritten for VALUE != 0"
+#endif
+
 	.text
 
 	.globl	__new_sem_wait
 	.type	__new_sem_wait,@function
 	.align	16
-	cfi_startproc
 __new_sem_wait:
-	/* First check for cancellation.  */
-	movl	%gs:CANCELHANDLING, %eax
-	andl	$0xfffffff9, %eax
-	cmpl	$8, %eax
-	je	5f
+.LSTARTCODE:
+	pushl	%ebx
+.Lpush_ebx:
+	pushl	%esi
+.Lpush_esi:
+	subl	$4, %esp
+.Lsub_esp:
+
+	movl	16(%esp), %ebx
+
+	movl	(%ebx), %eax
+2:	testl	%eax, %eax
+	je	1f
+
+	leal	-1(%eax), %edx
+	LOCK
+	cmpxchgl %edx, (%ebx)
+	jne	2b
+7:	xorl	%eax, %eax
+
+9:	movl	4(%esp), %esi
+	movl	8(%esp), %ebx
+	addl	$12, %esp
+.Ladd_esp:
+	ret
+
+.Lafter_ret:
+1:	LOCK
+	incl	NWAITERS(%ebx)
+
+.LcleanupSTART:
+6:	call	__pthread_enable_asynccancel
+	movl	%eax, (%esp)
+
+	xorl	%esi, %esi
+	movl	$SYS_futex, %eax
+	movl	%esi, %ecx
+	movl	%esi, %edx
+	ENTER_KERNEL
+	movl	%eax, %esi
+
+	movl	(%esp), %eax
+	call	__pthread_disable_asynccancel
+.LcleanupEND:
+
+	testl	%esi, %esi
+	je	3f
+	cmpl	$-EWOULDBLOCK, %esi
+	jne	4f
+
+3:
+	movl	(%ebx), %eax
+5:	testl	%eax, %eax
+	je	6b
+
+	leal	-1(%eax), %edx
+	LOCK
+	cmpxchgl %edx, (%ebx)
+	jne	5b
+
+	LOCK
+	decl	NWAITERS(%ebx)
+	jmp	7b
+
+4:	LOCK
+	decl	NWAITERS(%ebx)
+
+	negl	%esi
+#ifdef PIC
+	call	__i686.get_pc_thunk.bx
+#else
+	movl	$8f, %ebx
+8:
+#endif
+	addl	$_GLOBAL_OFFSET_TABLE_, %ebx
+#if USE___THREAD
+# ifdef NO_TLS_DIRECT_SEG_REFS
+	movl	errno@gotntpoff(%ebx), %edx
+	addl	%gs:0, %edx
+	movl	%esi, (%edx)
+# else
+	movl	errno@gotntpoff(%ebx), %edx
+	movl	%esi, %gs:(%edx)
+# endif
+#else
+	call	__errno_location@plt
+	movl	%esi, (%eax)
+#endif
+	orl	$-1, %eax
+
+	jmp	9b
+	.size	__new_sem_wait,.-__new_sem_wait
+	versioned_symbol(libpthread, __new_sem_wait, sem_wait, GLIBC_2_1)
+
+
+	.type	sem_wait_cleanup,@function
+sem_wait_cleanup:
+	LOCK
+	decl	NWAITERS(%ebx)
+	movl	%eax, (%esp)
+.LcallUR:
+	call	_Unwind_Resume@PLT
+	hlt
+.LENDCODE:
+	.size	sem_wait_cleanup,.-sem_wait_cleanup
+
+
+	.section .gcc_except_table,"a",@progbits
+.LexceptSTART:
+	.byte	0xff				# @LPStart format (omit)
+	.byte	0xff				# @TType format (omit)
+	.byte	0x01				# call-site format
+						# DW_EH_PE_uleb128
+	.uleb128 .Lcstend-.Lcstbegin
+.Lcstbegin:
+	.uleb128 .LcleanupSTART-.LSTARTCODE
+	.uleb128 .LcleanupEND-.LcleanupSTART
+	.uleb128 sem_wait_cleanup-.LSTARTCODE
+	.uleb128  0
+	.uleb128 .LcallUR-.LSTARTCODE
+	.uleb128 .LENDCODE-.LcallUR
+	.uleb128 0
+	.uleb128  0
+.Lcstend:
+
+
+	.section .eh_frame,"a",@progbits
+.LSTARTFRAME:
+	.long	.LENDCIE-.LSTARTCIE		# Length of the CIE.
+.LSTARTCIE:
+	.long	0				# CIE ID.
+	.byte	1				# Version number.
+#ifdef SHARED
+	.string	"zPLR"				# NUL-terminated augmentation
+						# string.
+#else
+	.string	"zPL"				# NUL-terminated augmentation
+						# string.
+#endif
+	.uleb128 1				# Code alignment factor.
+	.sleb128 -4				# Data alignment factor.
+	.byte	8				# Return address register
+						# column.
+#ifdef SHARED
+	.uleb128 7				# Augmentation value length.
+	.byte	0x9b				# Personality: DW_EH_PE_pcrel
+						# + DW_EH_PE_sdata4
+						# + DW_EH_PE_indirect
+	.long	DW.ref.__gcc_personality_v0-.
+	.byte	0x1b				# LSDA Encoding: DW_EH_PE_pcrel
+						# + DW_EH_PE_sdata4.
+	.byte	0x1b				# FDE Encoding: DW_EH_PE_pcrel
+						# + DW_EH_PE_sdata4.
+#else
+	.uleb128 6				# Augmentation value length.
+	.byte	0x0				# Personality: absolute
+	.long	__gcc_personality_v0
+	.byte	0x0				# LSDA Encoding: absolute
+#endif
+	.byte 0x0c				# DW_CFA_def_cfa
+	.uleb128 4
+	.uleb128 4
+	.byte	0x88				# DW_CFA_offset, column 0x10
+	.uleb128 1
+	.align 4
+.LENDCIE:
+
+	.long	.LENDFDE-.LSTARTFDE		# Length of the FDE.
+.LSTARTFDE:
+	.long	.LSTARTFDE-.LSTARTFRAME		# CIE pointer.
+#ifdef SHARED
+	.long	.LSTARTCODE-.			# PC-relative start address
+						# of the code.
+#else
+	.long	.LSTARTCODE			# Start address of the code.
+#endif
+	.long	.LENDCODE-.LSTARTCODE		# Length of the code.
+	.uleb128 4				# Augmentation size
+#ifdef SHARED
+	.long	.LexceptSTART-.
+#else
+	.long	.LexceptSTART
+#endif
 
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Lpush_ebx-.LSTARTCODE
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 8
+	.byte   0x83				# DW_CFA_offset %ebx
+        .uleb128 2
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Lpush_esi-.Lpush_ebx
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 12
+	.byte   0x86				# DW_CFA_offset %esi
+        .uleb128 3
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Lsub_esp-.Lpush_esi
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 16
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Ladd_esp-.Lsub_esp
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 4
+	.byte	0xc3				# DW_CFA_restore %ebx
+	.byte	0xc6				# DW_CFA_restore %esi
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Lafter_ret-.Ladd_esp
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 16
+	.byte   0x83				# DW_CFA_offset %ebx
+        .uleb128 2
+	.byte   0x86				# DW_CFA_offset %esi
+        .uleb128 3
+	.align	4
+.LENDFDE:
+
+
+#ifdef SHARED
+	.hidden	DW.ref.__gcc_personality_v0
+	.weak	DW.ref.__gcc_personality_v0
+	.section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
+	.align	4
+	.type	DW.ref.__gcc_personality_v0, @object
+	.size	DW.ref.__gcc_personality_v0, 4
+DW.ref.__gcc_personality_v0:
+	.long	__gcc_personality_v0
+#endif
+
+
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
+	.section ".text.compat", "ax"
+	.global	__old_sem_wait
+	.type	__old_sem_wait,@function
+	.align	16
+	cfi_startproc
+__old_sem_wait:
 	pushl	%ebx
 	cfi_adjust_cfa_offset(4)
 	pushl	%esi
@@ -52,9 +287,9 @@ __new_sem_wait:
 	cfi_adjust_cfa_offset(4)
 
 	movl	16(%esp), %ebx
-	cfi_offset(3, -8)		/* %ebx */
+	cfi_offset(ebx, -8)
 
-	cfi_offset(6, -12)		/* %esi */
+	cfi_offset(esi, -12)
 3:	movl	(%ebx), %eax
 2:	testl	%eax, %eax
 	je	1f
@@ -65,17 +300,17 @@ __new_sem_wait:
 	jne	2b
 	xorl	%eax, %eax
 
-	movl	4(%esp), %esi
-	cfi_restore(6)
+5:	movl	4(%esp), %esi
 	movl	8(%esp), %ebx
-	cfi_restore(3)
 	addl	$12, %esp
+	cfi_restore(ebx)
+	cfi_restore(esi)
 	cfi_adjust_cfa_offset(-12)
 	ret
 
 	cfi_adjust_cfa_offset(12)
-	cfi_offset(3, -8)		/* %ebx */
-	cfi_offset(6, -12)		/* %esi */
+	cfi_offset(ebx, -8)
+	cfi_offset(esi, -12)
 1:	call	__pthread_enable_asynccancel
 	movl	%eax, (%esp)
 
@@ -115,25 +350,8 @@ __new_sem_wait:
 	movl	%esi, (%eax)
 #endif
 	orl	$-1, %eax
-	movl	4(%esp), %esi
-	cfi_restore(6)
-	movl	8(%esp), %ebx
-	cfi_restore(3)
-	addl	$12, %esp
-	cfi_adjust_cfa_offset(-12)
-	ret
-
-5:	/* Canceled.  */
-	movl	$0xffffffff, %gs:RESULT
-	LOCK
-	orl	$0x10, %gs:CANCELHANDLING
-	movl	%gs:CLEANUP_JMP_BUF, %eax
-	jmp	HIDDEN_JUMPTARGET (__pthread_unwind)
+	jmp	5b
 	cfi_endproc
-	.size	__new_sem_wait,.-__new_sem_wait
-	versioned_symbol(libpthread, __new_sem_wait, sem_wait, GLIBC_2_1)
-#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
-	.global	__old_sem_wait
-__old_sem_wait = __new_sem_wait
+	.size	__old_sem_wait,.-__old_sem_wait
 	compat_symbol(libpthread, __old_sem_wait, sem_wait, GLIBC_2_0)
 #endif
diff --git a/nptl/sysdeps/unix/sysv/linux/internaltypes.h b/nptl/sysdeps/unix/sysv/linux/internaltypes.h
index 1dec19e57d..eff932cab2 100644
--- a/nptl/sysdeps/unix/sysv/linux/internaltypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/internaltypes.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2004, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -137,9 +137,16 @@ struct pthread_key_struct
 
 
 /* Semaphore variable structure.  */
-struct sem
+struct new_sem
 {
-  unsigned int count;
+  unsigned int value;
+  int private;
+  unsigned long int nwaiters;
+};
+
+struct old_sem
+{
+  unsigned int value;
 };
 
 
diff --git a/nptl/sysdeps/unix/sysv/linux/sem_post.c b/nptl/sysdeps/unix/sysv/linux/sem_post.c
index 671b43f7f7..f8bc695292 100644
--- a/nptl/sysdeps/unix/sysv/linux/sem_post.c
+++ b/nptl/sysdeps/unix/sysv/linux/sem_post.c
@@ -1,5 +1,5 @@
 /* sem_post -- post to a POSIX semaphore.  Generic futex-using version.
-   Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
 
@@ -29,10 +29,33 @@
 int
 __new_sem_post (sem_t *sem)
 {
+  struct new_sem *isem = (struct new_sem *) sem;
+
+  int nr = atomic_increment_val (&isem->value);
+  atomic_full_barrier ();
+  if (isem->nwaiters > 0)
+    {
+      int err = lll_futex_wake (&isem->value, 1);
+      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)
+int
+attribute_compat_text_section
+__old_sem_post (sem_t *sem)
+{
   int *futex = (int *) sem;
 
   int nr = atomic_increment_val (futex);
-  int err = lll_futex_wake (futex, nr);
+  int err = lll_futex_wake (futex, 1);
   if (__builtin_expect (err, 0) < 0)
     {
       __set_errno (-err);
@@ -40,8 +63,5 @@ __new_sem_post (sem_t *sem)
     }
   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
diff --git a/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c b/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c
index ef897c1e93..30f6a87df4 100644
--- a/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c
+++ b/nptl/sysdeps/unix/sysv/linux/sem_timedwait.c
@@ -1,5 +1,5 @@
 /* sem_timedwait -- wait on a semaphore.  Generic futex-using version.
-   Copyright (C) 2003 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
 
@@ -28,28 +28,39 @@
 #include <shlib-compat.h>
 
 
+extern void __sem_wait_cleanup (void *arg) attribute_hidden;
+
+
+void
+attribute_hidden
+__sem_wait_cleanup (void *arg)
+{
+  struct new_sem *isem = (struct new_sem *) arg;
+
+  atomic_decrement (&isem->nwaiters);
+}
+
+
 int
 sem_timedwait (sem_t *sem, const struct timespec *abstime)
 {
-  /* First check for cancellation.  */
-  CANCELLATION_P (THREAD_SELF);
-
-  int *futex = (int *) sem;
-  int val;
+  struct new_sem *isem = (struct new_sem *) sem;
   int err;
 
-  if (*futex > 0)
+  if (atomic_decrement_if_positive (&isem->value) > 0)
+    return 0;
+
+  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
     {
-      val = atomic_decrement_if_positive (futex);
-      if (val > 0)
-	return 0;
+      __set_errno (EINVAL);
+      return -1;
     }
 
-  err = -EINVAL;
-  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
-    goto error_return;
+  atomic_increment (&isem->nwaiters);
+
+  pthread_cleanup_push (__sem_wait_cleanup, isem);
 
-  do
+  while (1)
     {
       struct timeval tv;
       struct timespec rt;
@@ -70,7 +81,11 @@ sem_timedwait (sem_t *sem, const struct timespec *abstime)
       /* Already timed out?  */
       err = -ETIMEDOUT;
       if (sec < 0)
-	goto error_return;
+	{
+	  __set_errno (ETIMEDOUT);
+	  err = -1;
+	  break;
+	}
 
       /* Do wait.  */
       rt.tv_sec = sec;
@@ -79,21 +94,28 @@ sem_timedwait (sem_t *sem, const struct timespec *abstime)
       /* Enable asynchronous cancellation.  Required by the standard.  */
       int oldtype = __pthread_enable_asynccancel ();
 
-      err = lll_futex_timed_wait (futex, 0, &rt);
+      err = lll_futex_timed_wait (&isem->value, 0, &rt);
 
       /* Disable asynchronous cancellation.  */
       __pthread_disable_asynccancel (oldtype);
 
       if (err != 0 && err != -EWOULDBLOCK)
-	goto error_return;
+	{
+	  __set_errno (-err);
+	  err = -1;
+	  break;
+	}
 
-      val = atomic_decrement_if_positive (futex);
+      if (atomic_decrement_if_positive (&isem->value) > 0)
+	{
+	  err = 0;
+	  break;
+	}
     }
-  while (val <= 0);
 
-  return 0;
+  pthread_cleanup_pop (0);
+
+  atomic_decrement (&isem->nwaiters);
 
- error_return:
-  __set_errno (-err);
-  return -1;
+  return err;
 }
diff --git a/nptl/sysdeps/unix/sysv/linux/sem_wait.c b/nptl/sysdeps/unix/sysv/linux/sem_wait.c
index d1aa97571a..e35b6480f2 100644
--- a/nptl/sysdeps/unix/sysv/linux/sem_wait.c
+++ b/nptl/sysdeps/unix/sysv/linux/sem_wait.c
@@ -28,9 +28,66 @@
 #include <shlib-compat.h>
 
 
+void
+attribute_hidden
+__sem_wait_cleanup (void *arg)
+{
+  struct new_sem *isem = (struct new_sem *) arg;
+
+  atomic_decrement (&isem->nwaiters);
+}
+
+
 int
 __new_sem_wait (sem_t *sem)
 {
+  struct new_sem *isem = (struct new_sem *) sem;
+  int err;
+
+  if (atomic_decrement_if_positive (&isem->value) > 0)
+    return 0;
+
+  atomic_increment (&isem->nwaiters);
+
+  pthread_cleanup_push (__sem_wait_cleanup, isem);
+
+  while (1)
+    {
+      /* Enable asynchronous cancellation.  Required by the standard.  */
+      int oldtype = __pthread_enable_asynccancel ();
+
+      err = lll_futex_wait (&isem->value, 0);
+
+      /* Disable asynchronous cancellation.  */
+      __pthread_disable_asynccancel (oldtype);
+
+      if (err != 0 && err != -EWOULDBLOCK)
+	{
+	  __set_errno (-err);
+	  err = -1;
+	}
+
+      if (atomic_decrement_if_positive (&isem->value) > 0)
+	{
+	  err = 0;
+	  break;
+	}
+    }
+
+  pthread_cleanup_pop (0);
+
+  atomic_decrement (&isem->nwaiters);
+
+  return err;
+}
+versioned_symbol (libpthread, __new_sem_wait, sem_wait, GLIBC_2_1);
+
+
+#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_1)
+int
+attribute_compat_text_section
+__old_sem_wait (sem_t *sem)
+{
   int *futex = (int *) sem;
   int err;
 
@@ -53,8 +110,5 @@ __new_sem_wait (sem_t *sem)
   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
diff --git a/nptl/sysdeps/unix/sysv/linux/structsem.sym b/nptl/sysdeps/unix/sysv/linux/structsem.sym
new file mode 100644
index 0000000000..4f32c68da5
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/structsem.sym
@@ -0,0 +1,10 @@
+#include <stddef.h>
+#include <sched.h>
+#include <bits/pthreadtypes.h>
+#include "internaltypes.h"
+
+--
+
+VALUE		offsetof (struct new_sem, value)
+PRIVATE		offsetof (struct new_sem, private)
+NWAITERS	offsetof (struct new_sem, nwaiters)
diff --git a/nptl/sysdeps/unix/sysv/linux/x86_64/sem_post.S b/nptl/sysdeps/unix/sysv/linux/x86_64/sem_post.S
index 7f608a5974..1f5d0bba34 100644
--- a/nptl/sysdeps/unix/sysv/linux/x86_64/sem_post.S
+++ b/nptl/sysdeps/unix/sysv/linux/x86_64/sem_post.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2005, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -20,6 +20,7 @@
 #include <sysdep.h>
 #include <shlib-compat.h>
 #include <pthread-errnos.h>
+#include <structsem.h>
 
 #ifndef UP
 # define LOCK lock
@@ -37,19 +38,25 @@
 	.type	sem_post,@function
 	.align	16
 sem_post:
-	movl	$1, %edx
 	LOCK
-	xaddl	%edx, (%rdi)
+#if VALUE == 0
+	addl	$1, (%rdi)
+#else
+	addl	$1, VALUE(%rdi)
+#endif
+
+	cmpq	$0, NWAITERS(%rdi)
+	je	2f
 
 	movl	$SYS_futex, %eax
 	movl	$FUTEX_WAKE, %esi
-	incl	%edx
+	movl	$1, %edx
 	syscall
 
 	testq	%rax, %rax
 	js	1f
 
-	xorl	%eax, %eax
+2:	xorl	%eax, %eax
 	retq
 
 1:
diff --git a/nptl/sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S b/nptl/sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S
index 8c5c2a6974..1bb74c0368 100644
--- a/nptl/sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S
+++ b/nptl/sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S
@@ -20,6 +20,7 @@
 #include <sysdep.h>
 #include <shlib-compat.h>
 #include <pthread-errnos.h>
+#include <structsem.h>
 
 #ifndef UP
 # define LOCK lock
@@ -28,6 +29,7 @@
 #endif
 
 #define SYS_futex		202
+#define FUTEX_WAIT		0
 
 /* For the calculation see asm/vsyscall.h.  */
 #define VSYSCALL_ADDR_vgettimeofday	0xffffffffff600000
@@ -38,15 +40,23 @@
 	.globl	sem_timedwait
 	.type	sem_timedwait,@function
 	.align	16
-	cfi_startproc
 sem_timedwait:
+.LSTARTCODE:
+#if VALUE == 0
 	movl	(%rdi), %eax
+#else
+	movl	VALUE(%rdi), %eax
+#endif
 2:	testl	%eax, %eax
 	je	1f
 
 	leaq	-1(%rax), %rdx
 	LOCK
+#if VALUE == 0
 	cmpxchgl %edx, (%rdi)
+#else
+	cmpxchgl %edx, VALUE(%rdi)
+#endif
 	jne	2b
 
 	xorl	%eax, %eax
@@ -54,25 +64,25 @@ sem_timedwait:
 
 	/* Check whether the timeout value is valid.  */
 1:	pushq	%r12
-	cfi_adjust_cfa_offset(8)
+.Lpush_r12:
 	pushq	%r13
-	cfi_adjust_cfa_offset(8)
+.Lpush_r13:
 	pushq	%r14
-	cfi_adjust_cfa_offset(8)
+.Lpush_r14:
 	subq	$24, %rsp
-	cfi_adjust_cfa_offset(24)
+.Lsubq:
 
 	movq	%rdi, %r12
-	cfi_offset(12, -16)		/* %r12 */
 	movq	%rsi, %r13
-	cfi_offset(13, -24)		/* %r13 */
 
 	/* Check for invalid nanosecond field.  */
 	cmpq	$1000000000, 8(%r13)
 	movl	$EINVAL, %r14d
-	cfi_offset(14, -24)		/* %r14 */
 	jae	6f
 
+	LOCK
+	addq	$1, NWAITERS(%r12)
+
 7:	xorl	%esi, %esi
 	movq	%rsp, %rdi
 	movq	$VSYSCALL_ADDR_vgettimeofday, %rax
@@ -96,12 +106,17 @@ sem_timedwait:
 	movq	%rdi, (%rsp)	/* Store relative timeout.  */
 	movq	%rsi, 8(%rsp)
 
+.LcleanupSTART:
 	call	__pthread_enable_asynccancel
 	movl	%eax, 16(%rsp)
 
 	movq	%rsp, %r10
+#if VALUE == 0
 	movq	%r12, %rdi
-	xorl	%esi, %esi
+#else
+	leaq	VALUE(%r12), %rdi
+#endif
+	movl	$FUTEX_WAIT, %esi
 	movl	$SYS_futex, %eax
 	xorl	%edx, %edx
 	syscall
@@ -109,39 +124,47 @@ sem_timedwait:
 
 	movl	16(%rsp), %edi
 	call	__pthread_disable_asynccancel
+.LcleanupEND:
 
 	testq	%r14, %r14
 	je	9f
 	cmpq	$-EWOULDBLOCK, %r14
 	jne	3f
 
-9:	movl	(%r12), %eax
+9:
+#if VALUE == 0
+	movl	(%r12), %eax
+#else
+	movl	VALUE(%r12), %eax
+#endif
 8:	testl	%eax, %eax
 	je	7b
 
 	leaq	-1(%rax), %rcx
 	LOCK
+#if VALUE == 0
 	cmpxchgl %ecx, (%r12)
+#else
+	cmpxchgl %ecx, VALUE(%r12)
+#endif
 	jne	8b
 
 	xorl	%eax, %eax
-10:	addq	$24, %rsp
-	cfi_adjust_cfa_offset(-24)
+
+10:	LOCK
+	subq	$1, NWAITERS(%r12)
+
+	addq	$24, %rsp
+.Laddq:
 	popq	%r14
-	cfi_adjust_cfa_offset(-8)
-	cfi_restore(14)
+.Lpop_r14:
 	popq	%r13
-	cfi_adjust_cfa_offset(-8)
-	cfi_restore(13)
+.Lpop_r13:
 	popq	%r12
-	cfi_adjust_cfa_offset(-8)
-	cfi_restore(12)
+.Lpop_r12:
 	retq
 
-	cfi_adjust_cfa_offset(48)
-	cfi_offset(12, -16)		/* %r12 */
-	cfi_offset(13, -24)		/* %r13 */
-	cfi_offset(14, -32)		/* %r14 */
+.Lafter_retq:
 3:	negq	%r14
 6:
 #if USE___THREAD
@@ -154,5 +177,159 @@ sem_timedwait:
 
 	orl	$-1, %eax
 	jmp	10b
-	cfi_endproc
 	.size	sem_timedwait,.-sem_timedwait
+
+
+	.type	sem_timedwait_cleanup,@function
+sem_timedwait_cleanup:
+	LOCK
+	subq	$1, NWAITERS(%r12)
+	movq	%rax, %rdi
+.LcallUR:
+	call	_Unwind_Resume@PLT
+	hlt
+.LENDCODE:
+	.size	sem_timedwait_cleanup,.-sem_timedwait_cleanup
+
+
+	.section .gcc_except_table,"a",@progbits
+.LexceptSTART:
+	.byte	0xff				# @LPStart format (omit)
+	.byte	0xff				# @TType format (omit)
+	.byte	0x01				# call-site format
+						# DW_EH_PE_uleb128
+	.uleb128 .Lcstend-.Lcstbegin
+.Lcstbegin:
+	.uleb128 .LcleanupSTART-.LSTARTCODE
+	.uleb128 .LcleanupEND-.LcleanupSTART
+	.uleb128 sem_timedwait_cleanup-.LSTARTCODE
+	.uleb128  0
+	.uleb128 .LcallUR-.LSTARTCODE
+	.uleb128 .LENDCODE-.LcallUR
+	.uleb128 0
+	.uleb128  0
+.Lcstend:
+
+
+	.section .eh_frame,"a",@progbits
+.LSTARTFRAME:
+	.long	.LENDCIE-.LSTARTCIE		# Length of the CIE.
+.LSTARTCIE:
+	.long	0				# CIE ID.
+	.byte	1				# Version number.
+#ifdef SHARED
+	.string	"zPLR"				# NUL-terminated augmentation
+						# string.
+#else
+	.string	"zPL"				# NUL-terminated augmentation
+						# string.
+#endif
+	.uleb128 1				# Code alignment factor.
+	.sleb128 -8				# Data alignment factor.
+	.byte	16				# Return address register
+						# column.
+#ifdef SHARED
+	.uleb128 7				# Augmentation value length.
+	.byte	0x9b				# Personality: DW_EH_PE_pcrel
+						# + DW_EH_PE_sdata4
+						# + DW_EH_PE_indirect
+	.long	DW.ref.__gcc_personality_v0-.
+	.byte	0x1b				# LSDA Encoding: DW_EH_PE_pcrel
+						# + DW_EH_PE_sdata4.
+	.byte	0x1b				# FDE Encoding: DW_EH_PE_pcrel
+						# + DW_EH_PE_sdata4.
+#else
+	.uleb128 10				# Augmentation value length.
+	.byte	0x0				# Personality: absolute
+	.quad	__gcc_personality_v0
+	.byte	0x0				# LSDA Encoding: absolute
+#endif
+	.byte 0x0c				# DW_CFA_def_cfa
+	.uleb128 7
+	.uleb128 8
+	.byte	0x90				# DW_CFA_offset, column 0x10
+	.uleb128 1
+	.align 8
+.LENDCIE:
+
+	.long	.LENDFDE-.LSTARTFDE		# Length of the FDE.
+.LSTARTFDE:
+	.long	.LSTARTFDE-.LSTARTFRAME		# CIE pointer.
+#ifdef SHARED
+	.long	.LSTARTCODE-.			# PC-relative start address
+						# of the code.
+	.long	.LENDCODE-.LSTARTCODE		# Length of the code.
+	.uleb128 4				# Augmentation size
+	.long	.LexceptSTART-.
+#else
+	.quad	.LSTARTCODE			# Start address of the code.
+	.quad	.LENDCODE-.LSTARTCODE		# Length of the code.
+	.uleb128 8				# Augmentation size
+	.quad	.LexceptSTART
+#endif
+
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Lpush_r12-.LSTARTCODE
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 16
+	.byte   0x8c				# DW_CFA_offset %r12
+        .uleb128 2
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Lpush_r13-.Lpush_r12
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 24
+	.byte   0x8d				# DW_CFA_offset %r13
+        .uleb128 3
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Lpush_r14-.Lpush_r13
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 32
+	.byte   0x8e				# DW_CFA_offset %r14
+        .uleb128 4
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Lsubq-.Lpush_r14
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 56
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Laddq-.Lsubq
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 32
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Lpop_r14-.Laddq
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 24
+	.byte	0xce				# DW_CFA_restore %r14
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Lpop_r13-.Lpop_r14
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 16
+	.byte	0xcd				# DW_CFA_restore %r13
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Lpop_r12-.Lpop_r13
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 8
+	.byte	0xcc				# DW_CFA_restore %r12
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Lafter_retq-.Lpop_r12
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 56
+	.byte   0x8c				# DW_CFA_offset %r12
+        .uleb128 2
+	.byte   0x8d				# DW_CFA_offset %r13
+        .uleb128 3
+	.byte   0x8e				# DW_CFA_offset %r14
+        .uleb128 4
+	.align	8
+.LENDFDE:
+
+
+#ifdef SHARED
+	.hidden	DW.ref.__gcc_personality_v0
+	.weak	DW.ref.__gcc_personality_v0
+	.section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
+	.align	8
+	.type	DW.ref.__gcc_personality_v0, @object
+	.size	DW.ref.__gcc_personality_v0, 8
+DW.ref.__gcc_personality_v0:
+	.quad	__gcc_personality_v0
+#endif
diff --git a/nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S b/nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S
index 5bd78eb944..e958d63f55 100644
--- a/nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S
+++ b/nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S
@@ -20,6 +20,7 @@
 #include <sysdep.h>
 #include <shlib-compat.h>
 #include <pthread-errnos.h>
+#include <structsem.h>
 
 #ifndef UP
 # define LOCK lock
@@ -28,6 +29,7 @@
 #endif
 
 #define SYS_futex		202
+#define FUTEX_WAIT		0
 
 
 	.text
@@ -35,57 +37,88 @@
 	.globl	sem_wait
 	.type	sem_wait,@function
 	.align	16
-	cfi_startproc
 sem_wait:
+.LSTARTCODE:
 	pushq	%r12
-	cfi_adjust_cfa_offset(8)
-	cfi_offset(12, -16)
+.Lpush_r12:
 	pushq	%r13
-	cfi_adjust_cfa_offset(8)
+.Lpush_r13:
 	movq	%rdi, %r13
-	cfi_offset(13, -24)
 
-3:	movl	(%r13), %eax
+#if VALUE == 0
+	movl	(%r13), %eax
+#else
+	movl	VALUE(%r13), %eax
+#endif
 2:	testl	%eax, %eax
 	je	1f
 
-	leaq	-1(%rax), %rdx
+	leal	-1(%rax), %edx
 	LOCK
+#if VALUE == 0
 	cmpxchgl %edx, (%r13)
+#else
+	cmpxchgl %edx, VALUE(%r13)
+#endif
 	jne	2b
-	xorl	%eax, %eax
 
-	popq	%r13
-	cfi_adjust_cfa_offset(-8)
-	cfi_restore(13)
+7:	xorl	%eax, %eax
+
+9:	popq	%r13
+.Lpop_r13:
 	popq	%r12
-	cfi_adjust_cfa_offset(-8)
-	cfi_restore(12)
+.Lpop_r12:
 
 	retq
 
-	cfi_adjust_cfa_offset(16)
-	cfi_offset(12, -16)
-	cfi_offset(13, -24)
-1:	call	__pthread_enable_asynccancel
+.Lafter_retq:
+1:	LOCK
+	addq	$1, NWAITERS(%r13)
+
+.LcleanupSTART:
+6:	call	__pthread_enable_asynccancel
 	movl	%eax, %r8d
 
 	xorq	%r10, %r10
 	movl	$SYS_futex, %eax
 	movq	%r13, %rdi
-	movq	%r10, %rsi
-	movq	%r10, %rdx
+	movl	$FUTEX_WAIT, %esi
+	xorl	%edx, %edx
 	syscall
 	movq	%rax, %r12
 
 	movl	%r8d, %edi
 	call	__pthread_disable_asynccancel
+.LcleanupEND:
 
 	testq	%r12, %r12
-	je	3b
+	je	3f
 	cmpq	$-EWOULDBLOCK, %r12
-	je	3b
-	negq	%r12
+	jne	4f
+
+3:
+#if VALUE == 0
+	movl	(%r13), %eax
+#else
+	movl	VALUE(%r13), %eax
+#endif
+5:	testl	%eax, %eax
+	je	6b
+
+	leal	-1(%rax), %edx
+	LOCK
+#if VALUE == 0
+	cmpxchgl %edx, (%r13)
+#else
+	cmpxchgl %edx, VALUE(%r13)
+#endif
+	jne	5b
+
+	LOCK
+	subq	$1, NWAITERS(%r13)
+	jmp	7b
+
+4:	negq	%r12
 #if USE___THREAD
 	movq	errno@gottpoff(%rip), %rdx
 	movl	%r12d, %fs:(%rdx)
@@ -95,13 +128,142 @@ sem_wait:
 #endif
 	orl	$-1, %eax
 
-	popq	%r13
-	cfi_adjust_cfa_offset(-8)
-	cfi_restore(13)
-	popq	%r12
-	cfi_adjust_cfa_offset(-8)
-	cfi_restore(12)
+	LOCK
+	subq	$1, NWAITERS(%r13)
 
-	retq
-	cfi_endproc
+	jmp 9b
 	.size	sem_wait,.-sem_wait
+
+
+	.type	sem_wait_cleanup,@function
+sem_wait_cleanup:
+	LOCK
+	subq	$1, NWAITERS(%r13)
+	movq	%rax, %rdi
+.LcallUR:
+	call	_Unwind_Resume@PLT
+	hlt
+.LENDCODE:
+	.size	sem_wait_cleanup,.-sem_wait_cleanup
+
+
+	.section .gcc_except_table,"a",@progbits
+.LexceptSTART:
+	.byte	0xff				# @LPStart format (omit)
+	.byte	0xff				# @TType format (omit)
+	.byte	0x01				# call-site format
+						# DW_EH_PE_uleb128
+	.uleb128 .Lcstend-.Lcstbegin
+.Lcstbegin:
+	.uleb128 .LcleanupSTART-.LSTARTCODE
+	.uleb128 .LcleanupEND-.LcleanupSTART
+	.uleb128 sem_wait_cleanup-.LSTARTCODE
+	.uleb128  0
+	.uleb128 .LcallUR-.LSTARTCODE
+	.uleb128 .LENDCODE-.LcallUR
+	.uleb128 0
+	.uleb128  0
+.Lcstend:
+
+
+	.section .eh_frame,"a",@progbits
+.LSTARTFRAME:
+	.long	.LENDCIE-.LSTARTCIE		# Length of the CIE.
+.LSTARTCIE:
+	.long	0				# CIE ID.
+	.byte	1				# Version number.
+#ifdef SHARED
+	.string	"zPLR"				# NUL-terminated augmentation
+						# string.
+#else
+	.string	"zPL"				# NUL-terminated augmentation
+						# string.
+#endif
+	.uleb128 1				# Code alignment factor.
+	.sleb128 -8				# Data alignment factor.
+	.byte	16				# Return address register
+						# column.
+#ifdef SHARED
+	.uleb128 7				# Augmentation value length.
+	.byte	0x9b				# Personality: DW_EH_PE_pcrel
+						# + DW_EH_PE_sdata4
+						# + DW_EH_PE_indirect
+	.long	DW.ref.__gcc_personality_v0-.
+	.byte	0x1b				# LSDA Encoding: DW_EH_PE_pcrel
+						# + DW_EH_PE_sdata4.
+	.byte	0x1b				# FDE Encoding: DW_EH_PE_pcrel
+						# + DW_EH_PE_sdata4.
+#else
+	.uleb128 10				# Augmentation value length.
+	.byte	0x0				# Personality: absolute
+	.quad	__gcc_personality_v0
+	.byte	0x0				# LSDA Encoding: absolute
+#endif
+	.byte 0x0c				# DW_CFA_def_cfa
+	.uleb128 7
+	.uleb128 8
+	.byte	0x90				# DW_CFA_offset, column 0x10
+	.uleb128 1
+	.align 8
+.LENDCIE:
+
+	.long	.LENDFDE-.LSTARTFDE		# Length of the FDE.
+.LSTARTFDE:
+	.long	.LSTARTFDE-.LSTARTFRAME		# CIE pointer.
+#ifdef SHARED
+	.long	.LSTARTCODE-.			# PC-relative start address
+						# of the code.
+	.long	.LENDCODE-.LSTARTCODE		# Length of the code.
+	.uleb128 4				# Augmentation size
+	.long	.LexceptSTART-.
+#else
+	.quad	.LSTARTCODE			# Start address of the code.
+	.quad	.LENDCODE-.LSTARTCODE		# Length of the code.
+	.uleb128 8				# Augmentation size
+	.quad	.LexceptSTART
+#endif
+
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Lpush_r12-.LSTARTCODE
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 16
+	.byte   0x8c				# DW_CFA_offset %r12
+        .uleb128 2
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Lpush_r13-.Lpush_r12
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 24
+	.byte   0x8d				# DW_CFA_offset %r13
+        .uleb128 3
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Lpop_r13-.Lpush_r13
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 16
+	.byte	0xcd				# DW_CFA_restore %r13
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Lpop_r12-.Lpop_r13
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 8
+	.byte	0xcc				# DW_CFA_restore %r12
+	.byte	4				# DW_CFA_advance_loc4
+	.long	.Lafter_retq-.Lpop_r12
+	.byte	14				# DW_CFA_def_cfa_offset
+	.uleb128 24
+	.byte   0x8c				# DW_CFA_offset %r12
+        .uleb128 2
+	.byte   0x8d				# DW_CFA_offset %r13
+        .uleb128 3
+	.align	8
+.LENDFDE:
+
+
+#ifdef SHARED
+	.hidden	DW.ref.__gcc_personality_v0
+	.weak	DW.ref.__gcc_personality_v0
+	.section .gnu.linkonce.d.DW.ref.__gcc_personality_v0,"aw",@progbits
+	.align	8
+	.type	DW.ref.__gcc_personality_v0, @object
+	.size	DW.ref.__gcc_personality_v0, 8
+DW.ref.__gcc_personality_v0:
+	.quad	__gcc_personality_v0
+#endif
diff --git a/nptl/tst-typesizes.c b/nptl/tst-typesizes.c
index db8936f5f4..17a1e297d3 100644
--- a/nptl/tst-typesizes.c
+++ b/nptl/tst-typesizes.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2005.
 
@@ -59,7 +59,8 @@ do_test (void)
   TEST_TYPE2 (pthread_rwlockattr_t, struct pthread_rwlockattr);
   TEST_TYPE2 (pthread_barrier_t, struct pthread_barrier);
   TEST_TYPE2 (pthread_barrierattr_t, struct pthread_barrierattr);
-  TEST_TYPE2 (sem_t, struct sem);
+  TEST_TYPE2 (sem_t, struct new_sem);
+  TEST_TYPE2 (sem_t, struct old_sem);
 
   return result;
 }