summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--nptl/ChangeLog53
-rw-r--r--nptl/Makefile2
-rw-r--r--nptl/pthread_mutex_destroy.c4
-rw-r--r--nptl/pthread_mutex_init.c5
-rw-r--r--nptl/pthread_mutex_lock.c8
-rw-r--r--nptl/pthread_mutex_timedlock.c9
-rw-r--r--nptl/pthread_mutex_trylock.c7
-rw-r--r--nptl/pthread_mutex_unlock.c21
-rw-r--r--nptl/sysdeps/i386/tls.h6
-rw-r--r--nptl/sysdeps/ia64/tls.h4
-rw-r--r--nptl/sysdeps/powerpc/tls.h4
-rw-r--r--nptl/sysdeps/pthread/pthread_cond_timedwait.c2
-rw-r--r--nptl/sysdeps/pthread/pthread_cond_wait.c2
-rw-r--r--nptl/sysdeps/s390/tls.h4
-rw-r--r--nptl/sysdeps/sh/tls.h7
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h3
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S19
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S19
-rw-r--r--nptl/sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h3
-rw-r--r--nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h8
-rw-r--r--nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c1
-rw-r--r--nptl/sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h8
-rw-r--r--nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h3
-rw-r--r--nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h3
-rw-r--r--nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S3
-rw-r--r--nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S3
-rw-r--r--nptl/sysdeps/x86_64/tls.h4
-rw-r--r--nptl/tst-mutex8.c367
-rw-r--r--nptl/tst-mutex9.c194
29 files changed, 700 insertions, 76 deletions
diff --git a/nptl/ChangeLog b/nptl/ChangeLog
index 26b8909e7f..c6047d3b3b 100644
--- a/nptl/ChangeLog
+++ b/nptl/ChangeLog
@@ -1,3 +1,56 @@
+2003-06-22  Ulrich Drepper  <drepper@redhat.com>
+
+	* pthreadP.h (__pthread_mutex_init_internal): Mark hidden.
+	(__pthread_mutex_lock_internal): Likewise.
+	(__pthread_mutex_unlock_internal): Likewise.
+	(__pthread_mutex_unlock_usercnt): Declare.
+	* pthread_mutex_destroy.c: Always fail if used in any way.
+	* pthread_mutex_init.c: Update comment.
+	* pthread_mutex_lock.c: If NO_INCR is not defined adjust __nusers.
+	* pthread_mutex_timedlock.c: Adjust __nusers.
+	* pthread_mutex_trylock.c: Adjust __nusers.
+	* pthread_mutex_unlock.c: Old code is in __pthread_mutex_unlock_usercnt
+	and public interfaces are wrapper with pass additional parameter.
+	__pthread_mutex_unlock_usercnt does not adjust __nusers if second
+	parameter zero.
+	* tst-mutex8.c: New file.
+	* Makefile (tests): Add tst-mutex8.
+	* sysdeps/pthread/pthread_cond_timedwait.c: Call
+	__pthread_mutex_unlock_usercnt.
+	* sysdeps/pthread/pthread_cond_wait.c: Likewise.
+	* sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise.
+	* sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise.
+	* sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise.
+	* sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise.
+	* sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c: Define NO_INCR.
+	* sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_mutex_t):
+	Add __nusers.
+	* sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise.
+	* sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise.
+	* sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise.
+	* sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise.
+	* sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise.
+
+	* pthread_mutex_lock.c: Don't store THREAD_ID in __owner, use TID.
+	* pthread_mutex_timedlock.c: Likewise.
+	* pthread_mutex_trylock.c: Adjust __nusers.
+	* pthread_mutex_unlock.c: Compare with TID not THREAD_ID.
+	* tst-mutex9.c: New file.
+	* Makefile (tests): Add tst-mutex9.
+	* sysdeps/i386/tls.h: Remove THREAD_ID definition.
+	* sysdeps/ia64/tls.h: Likewise.
+	* sysdeps/powerpc/tls.h: Likewise.
+	* sysdeps/s390/tls.h: Likewise.
+	* sysdeps/sh/tls.h: Likewise.
+	* sysdeps/x86_64/tls.h: Likewise.
+	* sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_mutex_t):
+	Change type of __owner.
+	* sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise.
+	* sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise.
+	* sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise.
+	* sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise.
+	* sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise.
+
 2003-06-19  Jakub Jelinek  <jakub@redhat.com>
 
 	* sysdeps/unix/sysv/linux/ia64/sem_post.c: Move to...
diff --git a/nptl/Makefile b/nptl/Makefile
index 349f3ac312..a6aa8c2666 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -187,7 +187,7 @@ omit-deps = $(unix-syscalls:%=ptw-%)
 
 tests = tst-attr1 tst-attr2 \
 	tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex5 tst-mutex6 \
-	tst-mutex7 \
+	tst-mutex7 tst-mutex8 tst-mutex9 \
 	tst-spin1 tst-spin2 tst-spin3 \
 	tst-cond1 tst-cond2 tst-cond3 tst-cond4 tst-cond5 tst-cond6 tst-cond7 \
 	tst-cond8 tst-cond9 tst-cond10 tst-cond11 \
diff --git a/nptl/pthread_mutex_destroy.c b/nptl/pthread_mutex_destroy.c
index dec390c552..91ccfb0d29 100644
--- a/nptl/pthread_mutex_destroy.c
+++ b/nptl/pthread_mutex_destroy.c
@@ -25,9 +25,7 @@ int
 __pthread_mutex_destroy (mutex)
      pthread_mutex_t *mutex;
 {
-  if (__builtin_expect (mutex->__data.__kind == PTHREAD_MUTEX_ERRORCHECK_NP,
-			0)
-      && lll_mutex_trylock (mutex->__data.__lock) != 0)
+  if (mutex->__data.__nusers != 0)
     return EBUSY;
 
   return 0;
diff --git a/nptl/pthread_mutex_init.c b/nptl/pthread_mutex_init.c
index 038e09d008..a95f97ad4f 100644
--- a/nptl/pthread_mutex_init.c
+++ b/nptl/pthread_mutex_init.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -48,7 +48,8 @@ __pthread_mutex_init (mutex, mutexattr)
 
   /* Default values: mutex not used yet.  */
   // mutex->__count = 0;	already done by memset
-  // mutex->__owner = NULL;	already done by memset
+  // mutex->__owner = 0;	already done by memset
+  // mutex->__nusers = 0;	already done by memset
 
   return 0;
 }
diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c
index 4fdb13718c..9c61aa75f6 100644
--- a/nptl/pthread_mutex_lock.c
+++ b/nptl/pthread_mutex_lock.c
@@ -31,7 +31,7 @@ int
 __pthread_mutex_lock (mutex)
      pthread_mutex_t *mutex;
 {
-  struct pthread *id = THREAD_ID;
+  pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
 
   switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP))
     {
@@ -55,6 +55,9 @@ __pthread_mutex_lock (mutex)
 	  /* Record the ownership.  */
 	  mutex->__data.__owner = id;
 	  mutex->__data.__count = 1;
+#ifndef NO_INCR
+	  ++mutex->__data.__nusers;
+#endif
 	}
       break;
 
@@ -74,6 +77,9 @@ __pthread_mutex_lock (mutex)
       LLL_MUTEX_LOCK (mutex->__data.__lock);
       /* Record the ownership.  */
       mutex->__data.__owner = id;
+#ifndef NO_INCR
+      ++mutex->__data.__nusers;
+#endif
       break;
     }
 
diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c
index f24f91dd3c..8efc422042 100644
--- a/nptl/pthread_mutex_timedlock.c
+++ b/nptl/pthread_mutex_timedlock.c
@@ -27,7 +27,7 @@ pthread_mutex_timedlock (mutex, abstime)
      pthread_mutex_t *mutex;
      const struct timespec *abstime;
 {
-  struct pthread *id = THREAD_ID;
+  pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
   int result = 0;
 
   /* We must not check ABSTIME here.  If the thread does not block
@@ -80,8 +80,11 @@ pthread_mutex_timedlock (mutex, abstime)
     }
 
   if (result == 0)
-    /* Record the ownership.  */
-    mutex->__data.__owner = id;
+    {
+      /* Record the ownership.  */
+      mutex->__data.__owner = id;
+      ++mutex->__data.__nusers;
+    }
 
  out:
   return result;
diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c
index c61d7d5852..b164e0205e 100644
--- a/nptl/pthread_mutex_trylock.c
+++ b/nptl/pthread_mutex_trylock.c
@@ -26,12 +26,13 @@ int
 __pthread_mutex_trylock (mutex)
      pthread_mutex_t *mutex;
 {
-  struct pthread *id = THREAD_ID;
+  pid_t *id;
 
   switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP))
     {
       /* Recursive mutex.  */
     case PTHREAD_MUTEX_RECURSIVE_NP:
+      id = THREAD_GETMEM (THREAD_SELF, tid);
       /* Check whether we already hold the mutex.  */
       if (mutex->__data.__owner == id)
 	{
@@ -49,6 +50,7 @@ __pthread_mutex_trylock (mutex)
 	  /* Record the ownership.  */
 	  mutex->__data.__owner = id;
 	  mutex->__data.__count = 1;
+	  ++mutex->__data.__nusers;
 	  return 0;
 	}
       break;
@@ -63,7 +65,8 @@ __pthread_mutex_trylock (mutex)
       if (lll_mutex_trylock (mutex->__data.__lock) == 0)
 	{
 	  /* Record the ownership.  */
-	  mutex->__data.__owner = id;
+	  mutex->__data.__owner = THREAD_GETMEM (THREAD_SELF, tid);
+	  ++mutex->__data.__nusers;
 
 	  return 0;
 	}
diff --git a/nptl/pthread_mutex_unlock.c b/nptl/pthread_mutex_unlock.c
index 975127d2b2..56b1cd4a9a 100644
--- a/nptl/pthread_mutex_unlock.c
+++ b/nptl/pthread_mutex_unlock.c
@@ -23,14 +23,16 @@
 
 
 int
-__pthread_mutex_unlock (mutex)
+internal_function
+__pthread_mutex_unlock_usercnt (mutex, decr)
      pthread_mutex_t *mutex;
+     bool decr;
 {
   switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP))
     {
     case PTHREAD_MUTEX_RECURSIVE_NP:
       /* Recursive mutex.  */
-      if (mutex->__data.__owner != THREAD_ID)
+      if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
 	return EPERM;
 
       if (--mutex->__data.__count != 0)
@@ -40,7 +42,7 @@ __pthread_mutex_unlock (mutex)
 
     case PTHREAD_MUTEX_ERRORCHECK_NP:
       /* Error checking mutex.  */
-      if (mutex->__data.__owner != THREAD_ID
+      if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)
 	  || ! lll_mutex_islocked (mutex->__data.__lock))
 	return EPERM;
       break;
@@ -54,12 +56,23 @@ __pthread_mutex_unlock (mutex)
     }
 
   /* Always reset the owner field.  */
-  mutex->__data.__owner = NULL;
+  mutex->__data.__owner = 0;
+  if (decr)
+    /* One less user.  */
+    --mutex->__data.__nusers;
 
   /* Unlock.  */
   lll_mutex_unlock (mutex->__data.__lock);
 
   return 0;
 }
+
+
+int
+__pthread_mutex_unlock (mutex)
+     pthread_mutex_t *mutex;
+{
+  return __pthread_mutex_unlock_usercnt (mutex, true);
+}
 strong_alias (__pthread_mutex_unlock, pthread_mutex_unlock)
 strong_alias (__pthread_mutex_unlock, __pthread_mutex_unlock_internal)
diff --git a/nptl/sysdeps/i386/tls.h b/nptl/sysdeps/i386/tls.h
index e0fc9ee284..85d6473380 100644
--- a/nptl/sysdeps/i386/tls.h
+++ b/nptl/sysdeps/i386/tls.h
@@ -248,13 +248,9 @@ union user_desc_init
 # define THREAD_SELF \
   ({ struct pthread *__self;						      \
      asm ("movl %%gs:%c1,%0" : "=r" (__self)				      \
-	  : "i" (offsetof (struct pthread, header.self)));			      \
+	  : "i" (offsetof (struct pthread, header.self)));		      \
      __self;})
 
-/* Identifier for the current thread.  THREAD_SELF is usable but
-   sometimes more expensive than necessary.  It is fine here.  */
-# define THREAD_ID THREAD_SELF
-
 
 /* Read member of the thread descriptor directly.  */
 # define THREAD_GETMEM(descr, member) \
diff --git a/nptl/sysdeps/ia64/tls.h b/nptl/sysdeps/ia64/tls.h
index 5ce74737a7..8a13a59d30 100644
--- a/nptl/sysdeps/ia64/tls.h
+++ b/nptl/sysdeps/ia64/tls.h
@@ -113,10 +113,6 @@ register struct pthread *__thread_self __asm__("r13");
 /* Return the thread descriptor for the current thread.  */
 # define THREAD_SELF (__thread_self - 1)
 
-/* Identifier for the current thread.  THREAD_SELF is usable but
-   sometimes more expensive than necessary as in this case.  */
-# define THREAD_ID __thread_self
-
 /* Access to data in the thread descriptor is easy.  */
 #define THREAD_GETMEM(descr, member) \
   descr->member
diff --git a/nptl/sysdeps/powerpc/tls.h b/nptl/sysdeps/powerpc/tls.h
index 70aff09e24..6573bb6b04 100644
--- a/nptl/sysdeps/powerpc/tls.h
+++ b/nptl/sysdeps/powerpc/tls.h
@@ -129,10 +129,6 @@ register void *__thread_register __asm__ ("r13");
     ((struct pthread *) (__thread_register \
 			 - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE))
 
-/* Identifier for the current thread.  THREAD_SELF is usable but
-   sometimes more expensive than necessary as in this case.  */
-# define THREAD_ID __thread_register
-
 /* Read member of the thread descriptor directly.  */
 # define THREAD_GETMEM(descr, member) ((void)(descr), (THREAD_SELF)->member)
 
diff --git a/nptl/sysdeps/pthread/pthread_cond_timedwait.c b/nptl/sysdeps/pthread/pthread_cond_timedwait.c
index 4dd6f2e02a..7f7d2086f2 100644
--- a/nptl/sysdeps/pthread/pthread_cond_timedwait.c
+++ b/nptl/sysdeps/pthread/pthread_cond_timedwait.c
@@ -56,7 +56,7 @@ __pthread_cond_timedwait (cond, mutex, abstime)
   lll_mutex_lock (cond->__data.__lock);
 
   /* Now we can release the mutex.  */
-  int err = __pthread_mutex_unlock_internal (mutex);
+  int err = __pthread_mutex_unlock_usercnt (mutex, 0);
   if (err)
     {
       lll_mutex_unlock (cond->__data.__lock);
diff --git a/nptl/sysdeps/pthread/pthread_cond_wait.c b/nptl/sysdeps/pthread/pthread_cond_wait.c
index da94cc2d6b..75edf3d158 100644
--- a/nptl/sysdeps/pthread/pthread_cond_wait.c
+++ b/nptl/sysdeps/pthread/pthread_cond_wait.c
@@ -82,7 +82,7 @@ __pthread_cond_wait (cond, mutex)
   lll_mutex_lock (cond->__data.__lock);
 
   /* Now we can release the mutex.  */
-  err = __pthread_mutex_unlock_internal (mutex);
+  err = __pthread_mutex_unlock_usercnt (mutex, 0);
   if (err)
     {
       lll_mutex_unlock (cond->__data.__lock);
diff --git a/nptl/sysdeps/s390/tls.h b/nptl/sysdeps/s390/tls.h
index 89e51ff228..06237ae15b 100644
--- a/nptl/sysdeps/s390/tls.h
+++ b/nptl/sysdeps/s390/tls.h
@@ -137,10 +137,6 @@ typedef struct
 /* Return the thread descriptor for the current thread.  */
 # define THREAD_SELF ((struct pthread *) __builtin_thread_pointer ())
 
-/* Identifier for the current thread.  THREAD_SELF is usable but
-   sometimes more expensive than necessary.  It is fine here.  */
-# define THREAD_ID THREAD_SELF
-
 /* Access to data in the thread descriptor is easy.  */
 #define THREAD_GETMEM(descr, member) \
   descr->member
diff --git a/nptl/sysdeps/sh/tls.h b/nptl/sysdeps/sh/tls.h
index a6cefa0b31..1e27b987e0 100644
--- a/nptl/sysdeps/sh/tls.h
+++ b/nptl/sysdeps/sh/tls.h
@@ -117,13 +117,6 @@ typedef struct
      __asm ("stc gbr,%0" : "=r" (__self));				      \
      __self - 1;})
 
-/* Identifier for the current thread.  THREAD_SELF is usable but
-   sometimes more expensive than necessary as in this case.  */
-# define THREAD_ID \
-  ({ struct pthread *__self;						      \
-     __asm ("stc gbr,%0" : "=r" (__self));				      \
-     __self;})
-
 /* Read member of the thread descriptor directly.  */
 # define THREAD_GETMEM(descr, member) (descr->member)
 
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
index 256589da0d..a098106629 100644
--- a/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
@@ -51,10 +51,11 @@ typedef union
   {
     int __lock;
     unsigned int __count;
-    struct pthread *__owner;
+    int __owner;
     /* KIND must stay at this position in the structure to maintain
        binary compatibility.  */
     int __kind;
+    unsigned int __nusers;
   } __data;
   char __size[__SIZEOF_PTHREAD_MUTEX_T];
   long int __align;
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S
index 5eec268b29..2f598980e5 100644
--- a/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S
@@ -72,9 +72,8 @@ __pthread_cond_timedwait:
 	movl	%eax, dep_mutex(%ebx)
 
 	/* Unlock the mutex.  */
-	pushl	%eax
-.Lpush4:
-	call	__pthread_mutex_unlock_internal
+	xorl	%edx, %edx
+	call	__pthread_mutex_unlock_usercnt
 
 	testl	%eax, %eax
 	jne	16f
@@ -90,7 +89,7 @@ __pthread_cond_timedwait:
 #else
 	leal	__condvar_cleanup, %eax
 #endif
-	subl	$40, %esp
+	subl	$44, %esp
 .Lsubl:
 	leal	28(%esp), %edx
 	movl	%esp, 8(%esp)
@@ -299,15 +298,15 @@ __pthread_cond_timedwait:
 	/* The initial unlocking of the mutex failed.  */
 16:
 .LSbl3:
-	movl	%eax, (%esp)
 	LOCK
 #if cond_lock == 0
 	subl	$1, (%ebx)
 #else
 	subl	$1, cond_lock(%ebx)
 #endif
-	jne	17f
+	jne	18b
 
+	movl	%eax, %esi
 #if cond_lock == 0
 	movl	%ebx, %eax
 #else
@@ -315,7 +314,7 @@ __pthread_cond_timedwait:
 #endif
 	call	__lll_mutex_unlock_wake
 
-17:	popl	%eax
+	movl	%esi, %eax
 	jmp	18b
 
 #if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS
@@ -411,10 +410,8 @@ versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
 	.uleb128 20
 	.byte	0x83				# DW_CFA_offset %ebx
 	.uleb128 5
-	.byte	0x40+.Lpush4-.Lpush_ebx		# DW_CFA_advance_loc+N
-	.byte	14				# DW_CFA_def_cfa_offset
-	.uleb128 24
-	.byte	0x40+.Lsubl-.Lpush4		# DW_CFA_advance_loc+N
+	.byte	2				# DW_CFA_advance_loc1
+	.byte	.Lsubl-.Lpush_ebx
 	.byte	14				# DW_CFA_def_cfa_offset
 	.uleb128 64
 	.byte	3				# DW_CFA_advance_loc2
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S
index 61d3d8d225..c98899ab05 100644
--- a/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S
@@ -127,9 +127,8 @@ __pthread_cond_wait:
 	movl	%eax, dep_mutex(%ebx)
 
 	/* Unlock the mutex.  */
-	pushl	%eax
-.Lpush4:
-	call	__pthread_mutex_unlock_internal
+	xorl	%edx, %edx
+	call	__pthread_mutex_unlock_usercnt
 
 	testl	%eax, %eax
 	jne	12f
@@ -145,7 +144,7 @@ __pthread_cond_wait:
 #else
 	leal	__condvar_cleanup, %eax
 #endif
-	subl	$32, %esp
+	subl	$36, %esp
 .Lsubl:
 	leal	20(%esp), %edx
 	movl	%esp, 8(%esp)
@@ -289,15 +288,15 @@ __pthread_cond_wait:
 	/* The initial unlocking of the mutex failed.  */
 12:
 .LSbl3:
-	movl	%eax, (%esp)
 	LOCK
 #if cond_lock == 0
 	subl	$1, (%ebx)
 #else
 	subl	$1, cond_lock(%ebx)
 #endif
-	jne	13f
+	jne	14b
 
+	movl	%eax, %esi
 #if cond_lock == 0
 	movl	%ebx, %eax
 #else
@@ -305,7 +304,7 @@ __pthread_cond_wait:
 #endif
 	call	__lll_mutex_unlock_wake
 
-13:	popl	%eax
+	movl	%esi, %eax
 	jmp	14b
 .LENDCODE:
 	.size	__pthread_cond_wait, .-__pthread_cond_wait
@@ -371,10 +370,8 @@ versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,
 	.uleb128 16
 	.byte	0x83				# DW_CFA_offset %ebx
 	.uleb128 4
-	.byte	0x40+.Lpush4-.Lpush_ebx		# DW_CFA_advance_loc+N
-	.byte	14				# DW_CFA_def_cfa_offset
-	.uleb128 20
-	.byte	0x40+.Lsubl-.Lpush4		# DW_CFA_advance_loc+N
+	.byte	2				# DW_CFA_advance_loc1
+	.byte	.Lsubl-.Lpush_ebx
 	.byte	14				# DW_CFA_def_cfa_offset
 	.uleb128 52
 	.byte	2				# DW_CFA_advance_loc1
diff --git a/nptl/sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h
index afd2f31465..c1eca62be7 100644
--- a/nptl/sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h
@@ -51,7 +51,8 @@ typedef union
   {
     int __lock;
     unsigned int __count;
-    struct pthread *__owner;
+    int __owner;
+    unsigned int __nusers;
     /* KIND must stay at this position in the structure to maintain
        binary compatibility.  */
     int __kind;
diff --git a/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h
index 8f3e64d75b..f827b3098d 100644
--- a/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h
@@ -66,10 +66,16 @@ typedef union
   {
     int __lock;
     unsigned int __count;
-    struct pthread *__owner;
+    int __owner;
+#if __WORDSIZE == 64
+    unsigned int __nusers;
+#endif
     /* KIND must stay at this position in the structure to maintain
        binary compatibility.  */
     int __kind;
+#if __WORDSIZE != 64
+    unsigned int __nusers;
+#endif
   } __data;
   char __size[__SIZEOF_PTHREAD_MUTEX_T];
   long int __align;
diff --git a/nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c b/nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c
index 893a5e932d..d253c72ea4 100644
--- a/nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c
+++ b/nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c
@@ -2,5 +2,6 @@
 
 #define LLL_MUTEX_LOCK(mutex) lll_mutex_cond_lock(mutex)
 #define __pthread_mutex_lock __pthread_mutex_cond_lock
+#define NO_INCR
 
 #include <nptl/pthread_mutex_lock.c>
diff --git a/nptl/sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h
index e34875f996..2d37683ee2 100644
--- a/nptl/sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h
@@ -65,10 +65,16 @@ typedef union
   {
     int __lock;
     unsigned int __count;
-    struct pthread *__owner;
+    int __owner;
+#if __WORDSIZE == 64
+    unsigned int __nusers;
+#endif
     /* KIND must stay at this position in the structure to maintain
        binary compatibility.  */
     int __kind;
+#if __WORDSIZE != 64
+    unsigned int __nusers;
+#endif
   } __data;
   char __size[__SIZEOF_PTHREAD_MUTEX_T];
   long int __align;
diff --git a/nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h
index 1eeae708e1..8236fd724a 100644
--- a/nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h
@@ -52,10 +52,11 @@ typedef union
   {
     int __lock;
     unsigned int __count;
-    struct pthread *__owner;
+    int __owner;
     /* KIND must stay at this position in the structure to maintain
        binary compatibility.  */
     int __kind;
+    unsigned int __nusers;
   } __data;
   char __size[__SIZEOF_PTHREAD_MUTEX_T];
   long int __align;
diff --git a/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h
index b2919ab4c6..ed3050e636 100644
--- a/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h
@@ -51,7 +51,8 @@ typedef union
   {
     int __lock;
     unsigned int __count;
-    struct pthread *__owner;
+    int __owner;
+    unsigned int __nusers;
     /* KIND must stay at this position in the structure to maintain
        binary compatibility.  */
     int __kind;
diff --git a/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S b/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S
index b64953ba83..b2b4449554 100644
--- a/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S
+++ b/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S
@@ -91,7 +91,8 @@ __pthread_cond_timedwait:
 
 	/* Unlock the mutex.  */
 2:	movq	16(%rsp), %rdi
-	callq	__pthread_mutex_unlock_internal
+	xorq	%rsi, %rsi
+	callq	__pthread_mutex_unlock_usercnt
 
 	testl	%eax, %eax
 	jne	16f
diff --git a/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S b/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S
index 2c6c6ce338..3942faf1ad 100644
--- a/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S
+++ b/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S
@@ -136,7 +136,8 @@ __pthread_cond_wait:
 
 	/* Unlock the mutex.  */
 2:	movq	16(%rsp), %rdi
-	callq	__pthread_mutex_unlock_internal
+	xorq	%rsi, %rsi
+	callq	__pthread_mutex_unlock_usercnt
 
 	testl	%eax, %eax
 	jne	12f
diff --git a/nptl/sysdeps/x86_64/tls.h b/nptl/sysdeps/x86_64/tls.h
index 973b242b4e..999c3aa55a 100644
--- a/nptl/sysdeps/x86_64/tls.h
+++ b/nptl/sysdeps/x86_64/tls.h
@@ -161,10 +161,6 @@ typedef struct
 	  : "i" (offsetof (struct pthread, header.self)));	 	      \
      __self;})
 
-/* Identifier for the current thread.  THREAD_SELF is usable but
-   sometimes more expensive than necessary.  It is fine here.  */
-# define THREAD_ID THREAD_SELF
-
 
 /* Read member of the thread descriptor directly.  */
 # define THREAD_GETMEM(descr, member) \
diff --git a/nptl/tst-mutex8.c b/nptl/tst-mutex8.c
new file mode 100644
index 0000000000..80ebe71f0c
--- /dev/null
+++ b/nptl/tst-mutex8.c
@@ -0,0 +1,367 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@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.  */
+
+/* This test checks behavior not required by POSIX.  */
+#include <errno.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static pthread_mutex_t *m;
+static pthread_barrier_t b;
+static pthread_cond_t c;
+static bool done;
+
+
+static void
+cl (void *arg)
+{
+  if (pthread_mutex_unlock (m) != 0)
+    {
+      puts ("cl: mutex_unlocked failed");
+      exit (1);
+    }
+}
+
+
+static void *
+tf (void *arg)
+{
+  if (pthread_mutex_lock (m) != 0)
+    {
+      puts ("tf: mutex_lock failed");
+      return (void *) 1l;
+    }
+
+  int e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      return (void *) 1l;
+    }
+
+  if (arg == NULL)
+    do
+      if (pthread_cond_wait (&c, m) != 0)
+	{
+	  puts ("tf: cond_wait failed");
+	  return (void *) 1l;
+	}
+    while (! done);
+  else
+    do
+      {
+	pthread_cleanup_push (cl, NULL);
+
+	if (pthread_cond_wait (&c, m) != 0)
+	  {
+	    puts ("tf: cond_wait failed");
+	    return (void *) 1l;
+	  }
+
+	pthread_cleanup_pop (0);
+      }
+    while (! done);
+
+  if (pthread_mutex_unlock (m) != 0)
+    {
+      puts ("tf: mutex_unlock failed");
+      return (void *) 1l;
+    }
+
+  return NULL;
+}
+
+
+static int
+check_type (const char *mas, pthread_mutexattr_t *ma)
+{
+  if (pthread_mutex_init (m, ma) != 0)
+    {
+      printf ("1st mutex_init failed for %s\n", mas);
+      return 1;
+    }
+
+  if (pthread_mutex_destroy (m) != 0)
+    {
+      printf ("immediate mutex_destroy failed for %s\n", mas);
+      return 1;
+    }
+
+  if (pthread_mutex_init (m, ma) != 0)
+    {
+      printf ("2nd mutex_init failed for %s\n", mas);
+      return 1;
+    }
+
+  if (pthread_mutex_lock (m) != 0)
+    {
+      printf ("1st mutex_lock failed for %s\n", mas);
+      return 1;
+    }
+
+  int e = pthread_mutex_destroy (m);
+  if (e == 0)
+    {
+      printf ("mutex_destroy of self-locked mutex succeeded for %s\n", mas);
+      return 1;
+    }
+  if (e != EBUSY)
+    {
+      printf ("mutex_destroy of self-locked mutex did not return EBUSY %s\n",
+	      mas);
+      return 1;
+    }
+
+  if (pthread_mutex_unlock (m) != 0)
+    {
+      printf ("1st mutex_unlock failed for %s\n", mas);
+      return 1;
+    }
+
+  if (pthread_mutex_trylock (m) != 0)
+    {
+      printf ("mutex_trylock failed for %s\n", mas);
+      return 1;
+    }
+
+  e = pthread_mutex_destroy (m);
+  if (e == 0)
+    {
+      printf ("mutex_destroy of self-trylocked mutex succeeded for %s\n", mas);
+      return 1;
+    }
+  if (e != EBUSY)
+    {
+      printf ("\
+mutex_destroy of self-trylocked mutex did not return EBUSY %s\n",
+	      mas);
+      return 1;
+    }
+
+  if (pthread_mutex_unlock (m) != 0)
+    {
+      printf ("2nd mutex_unlock failed for %s\n", mas);
+      return 1;
+    }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("1st create failed");
+      return 1;
+    }
+  done = false;
+
+  e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("1st barrier_wait failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (m) != 0)
+    {
+      printf ("2nd mutex_lock failed for %s\n", mas);
+      return 1;
+    }
+
+  if (pthread_mutex_unlock (m) != 0)
+    {
+      printf ("3rd mutex_unlock failed for %s\n", mas);
+      return 1;
+    }
+
+  e = pthread_mutex_destroy (m);
+  if (e == 0)
+    {
+      printf ("mutex_destroy of condvar-used mutex succeeded for %s\n", mas);
+      return 1;
+    }
+  if (e != EBUSY)
+    {
+      printf ("\
+mutex_destroy of condvar-used mutex did not return EBUSY for %s\n", mas);
+      return 1;
+    }
+
+  done = true;
+  if (pthread_cond_signal (&c) != 0)
+    {
+      puts ("cond_signal failed");
+      return 1;
+    }
+
+  void *r;
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("join failed");
+      return 1;
+    }
+  if (r != NULL)
+    {
+      puts ("thread didn't return NULL");
+      return 1;
+    }
+
+  if (pthread_mutex_destroy (m) != 0)
+    {
+      printf ("mutex_destroy after condvar-use failed for %s\n", mas);
+      return 1;
+    }
+
+  if (pthread_mutex_init (m, ma) != 0)
+    {
+      printf ("3rd mutex_init failed for %s\n", mas);
+      return 1;
+    }
+
+  if (pthread_create (&th, NULL, tf, (void *) 1) != 0)
+    {
+      puts ("2nd create failed");
+      return 1;
+    }
+  done = false;
+
+  e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("2nd barrier_wait failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (m) != 0)
+    {
+      printf ("3rd mutex_lock failed for %s\n", mas);
+      return 1;
+    }
+
+  if (pthread_mutex_unlock (m) != 0)
+    {
+      printf ("4th mutex_unlock failed for %s\n", mas);
+      return 1;
+    }
+
+  e = pthread_mutex_destroy (m);
+  if (e == 0)
+    {
+      printf ("2nd mutex_destroy of condvar-used mutex succeeded for %s\n",
+	      mas);
+      return 1;
+    }
+  if (e != EBUSY)
+    {
+      printf ("\
+2nd mutex_destroy of condvar-used mutex did not return EBUSY for %s\n",
+	      mas);
+      return 1;
+    }
+
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("cond_cancel failed");
+      return 1;
+    }
+
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("join failed");
+      return 1;
+    }
+  if (r != PTHREAD_CANCELED)
+    {
+      puts ("thread not canceled");
+      return 1;
+    }
+
+  if (pthread_mutex_destroy (m) != 0)
+    {
+      printf ("mutex_destroy after condvar-canceled failed for %s\n", mas);
+      return 1;
+    }
+
+  return 0;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_mutex_t mm;
+  m = &mm;
+
+  if (pthread_barrier_init (&b, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  if (pthread_cond_init (&c, NULL) != 0)
+    {
+      puts ("cond_init failed");
+      return 1;
+    }
+
+  puts ("check normal mutex");
+  int res = check_type ("normal", NULL);
+
+  pthread_mutexattr_t ma;
+  if (pthread_mutexattr_init (&ma) != 0)
+    {
+      puts ("1st mutexattr_init failed");
+      return 1;
+    }
+  if (pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_RECURSIVE) != 0)
+    {
+      puts ("1st mutexattr_settype failed");
+      return 1;
+    }
+  puts ("check recursive mutex");
+  res |= check_type ("recursive", &ma);
+  if (pthread_mutexattr_destroy (&ma) != 0)
+    {
+      puts ("1st mutexattr_destroy failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_init (&ma) != 0)
+    {
+      puts ("2nd mutexattr_init failed");
+      return 1;
+    }
+  if (pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_ERRORCHECK) != 0)
+    {
+      puts ("2nd mutexattr_settype failed");
+      return 1;
+    }
+  puts ("check error-checking mutex");
+  res |= check_type ("error-checking", &ma);
+  if (pthread_mutexattr_destroy (&ma) != 0)
+    {
+      puts ("2nd mutexattr_destroy failed");
+      return 1;
+    }
+
+  return res;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-mutex9.c b/nptl/tst-mutex9.c
new file mode 100644
index 0000000000..94e993c5cb
--- /dev/null
+++ b/nptl/tst-mutex9.c
@@ -0,0 +1,194 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@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 <pthread.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+
+static int
+do_test (void)
+{
+#if ! _POSIX_THREAD_PROCESS_SHARED
+
+  puts ("_POSIX_THREAD_PROCESS_SHARED not supported, test skipped");
+  return 0;
+
+#else
+
+  size_t ps = sysconf (_SC_PAGESIZE);
+  char tmpfname[] = "/tmp/tst-mutex9.XXXXXX";
+  char data[ps];
+  void *mem;
+  int fd;
+  pthread_mutex_t *m;
+  pthread_mutexattr_t a;
+  pid_t pid;
+  char *p;
+
+  fd = mkstemp (tmpfname);
+  if (fd == -1)
+    {
+      printf ("cannot open temporary file: %m\n");
+      return 1;
+    }
+
+  /* Make sure it is always removed.  */
+  unlink (tmpfname);
+
+  /* Create one page of data.  */
+  memset (data, '\0', ps);
+
+  /* Write the data to the file.  */
+  if (write (fd, data, ps) != (ssize_t) ps)
+    {
+      puts ("short write");
+      return 1;
+    }
+
+  mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  if (mem == MAP_FAILED)
+    {
+      printf ("mmap failed: %m\n");
+      return 1;
+    }
+
+  m = (pthread_mutex_t *) (((uintptr_t) mem + __alignof (pthread_mutex_t))
+			   & ~(__alignof (pthread_mutex_t) - 1));
+  p = (char *) (m + 1);
+
+  if (pthread_mutexattr_init (&a) != 0)
+    {
+      puts ("mutexattr_init failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("mutexattr_setpshared failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_settype (&a, PTHREAD_MUTEX_RECURSIVE) != 0)
+    {
+      puts ("mutexattr_settype failed");
+      return 1;
+    }
+
+  if (pthread_mutex_init (m, &a) != 0)
+    {
+      puts ("mutex_init failed");
+      return 1;
+    }
+
+  if (pthread_mutex_lock (m) != 0)
+    {
+      puts ("mutex_lock failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_destroy (&a) != 0)
+    {
+      puts ("mutexattr_destroy failed");
+      return 1;
+    }
+
+  puts ("going to fork now");
+  pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      return 1;
+    }
+  else if (pid == 0)
+    {
+      if (pthread_mutex_trylock (m) == 0)
+	{
+	  puts ("child: mutex_trylock succeeded");
+	  exit (1);
+	}
+
+      if (pthread_mutex_unlock (m) == 0)
+	{
+	  puts ("child: mutex_unlock succeeded");
+	  exit (1);
+	}
+
+      struct timeval tv;
+      gettimeofday (&tv, NULL);
+      struct timespec ts;
+      TIMEVAL_TO_TIMESPEC (&tv, &ts);
+      ts.tv_nsec += 500000000;
+      if (ts.tv_nsec >= 1000000000)
+	{
+	  ++ts.tv_sec;
+	  ts.tv_nsec -= 1000000000;
+	}
+
+      int e = pthread_mutex_timedlock (m, &ts);
+      if (e == 0)
+	{
+	  puts ("child: mutex_timedlock succeeded");
+	  exit (1);
+	}
+      if (e != ETIMEDOUT)
+	{
+	  puts ("child: mutex_timedlock didn't time out");
+	  exit (1);
+	}
+
+      alarm (1);
+
+      pthread_mutex_lock (m);
+
+      puts ("child: mutex_lock returned");
+
+      exit (0);
+    }
+
+  sleep (2);
+
+  int status;
+  if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
+    {
+      puts ("waitpid failed");
+      return 1;
+    }
+  if (! WIFSIGNALED (status))
+    {
+      puts ("child not killed by signal");
+      return 1;
+    }
+  if (WTERMSIG (status) != SIGALRM)
+    {
+      puts ("child not killed by SIGALRM");
+      return 1;
+    }
+
+  return 0;
+#endif
+}
+
+#define TIMEOUT 3
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"