about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--Versions.def1
-rw-r--r--nptl/ChangeLog53
-rw-r--r--nptl/Makefile7
-rw-r--r--nptl/Versions5
-rw-r--r--nptl/descr.h45
-rw-r--r--nptl/pthreadP.h28
-rw-r--r--nptl/pthread_create.c27
-rw-r--r--nptl/pthread_mutex_consistent.c36
-rw-r--r--nptl/pthread_mutex_init.c14
-rw-r--r--nptl/pthread_mutex_lock.c68
-rw-r--r--nptl/pthread_mutex_timedlock.c82
-rw-r--r--nptl/pthread_mutex_trylock.c88
-rw-r--r--nptl/pthread_mutex_unlock.c50
-rw-r--r--nptl/pthread_mutexattr_getpshared.c6
-rw-r--r--nptl/pthread_mutexattr_getrobust.c36
-rw-r--r--nptl/pthread_mutexattr_gettype.c6
-rw-r--r--nptl/pthread_mutexattr_setpshared.c8
-rw-r--r--nptl/pthread_mutexattr_setrobust.c43
-rw-r--r--nptl/pthread_mutexattr_settype.c6
-rw-r--r--nptl/sysdeps/pthread/pthread.h53
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h8
-rw-r--r--nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h15
-rw-r--r--nptl/tst-once3.c7
-rw-r--r--nptl/tst-robust1.c245
-rw-r--r--nptl/tst-robust2.c3
-rw-r--r--nptl/tst-robust3.c20
-rw-r--r--nptl/tst-robust4.c2
-rw-r--r--nptl/tst-robust5.c2
-rw-r--r--nptl/tst-robust6.c2
-rw-r--r--nptl/tst-typesizes.c68
31 files changed, 980 insertions, 58 deletions
diff --git a/ChangeLog b/ChangeLog
index ce5d95355a..36091ffc22 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2005-12-26  Ulrich Drepper  <drepper@redhat.com>
+
+	* Versions.def: Add GLIBC_2.4 for libpthread.
+
 2005-12-25  Ulrich Drepper  <drepper@redhat.com>
 
 	* stdlib/Makefile ($(objpfx)isomac.out): Move -I.. to the end so
diff --git a/Versions.def b/Versions.def
index 09cef140bf..d7be70386e 100644
--- a/Versions.def
+++ b/Versions.def
@@ -80,6 +80,7 @@ libpthread {
   GLIBC_2.3.2
   GLIBC_2.3.3
   GLIBC_2.3.4
+  GLIBC_2.4
   GLIBC_PRIVATE
 }
 libresolv {
diff --git a/nptl/ChangeLog b/nptl/ChangeLog
index 877c858118..acb6cd2a53 100644
--- a/nptl/ChangeLog
+++ b/nptl/ChangeLog
@@ -1,3 +1,56 @@
+2005-12-26  Ulrich Drepper  <drepper@redhat.com>
+
+	* pthreadP.h: Define PTHREAD_MUTEX_ROBUST_PRIVATE_NP,
+	PTHREAD_MUTEX_ROBUST_PRIVATE_RECURSIVE_NP,
+	PTHREAD_MUTEX_ROBUST_PRIVATE_ERRORCHECK_NP,
+	PTHREAD_MUTEX_ROBUST_PRIVATE_ADAPTIVE_NP,
+	PTHREAD_MUTEXATTR_FLAG_ROBUST, PTHREAD_MUTEXATTR_FLAG_PSHARED,
+	and PTHREAD_MUTEXATTR_FLAG_BITS.
+	* descr.h (struct pthread): Add robust_list field and define
+	ENQUEUE_MUTEX and DEQUEUE_MUTEX macros.
+	* pthread_mutexattr_getrobust.c: New file.
+	* pthread_mutexattr_setrobust.c: New file.
+	* pthread_mutex_consistent.c: New file.
+	* sysdeps/pthread/pthread.h: Declare pthread_mutexattr_getrobust,
+	pthread_mutexattr_setrobust, and pthread_mutex_consistent.
+	Define PTHREAD_MUTEX_STALLED_NP and PTHREAD_MUTEX_ROBUST_NP.
+	Adjust pthread_mutex_t initializers.
+	* nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Add __next
+	field to pthread_mutex_t.
+	* nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Add __next
+	and __prev field to pthread_mutex_t.
+	* Versions [GLIBC_2.4]: Export pthread_mutexattr_getrobust_np,
+	pthread_mutexattr_setrobust_np, and pthread_mutex_consistent_np.
+	* pthread_mutexattr_getpshared.c: Use PTHREAD_MUTEXATTR_FLAG_PSHARED
+	and PTHREAD_MUTEXATTR_FLAG_BITS macros instead of magic numbers.
+	* pthread_mutexattr_gettype.c: Likewise.
+	* pthread_mutexattr_setpshared.c: Likewise.
+	* pthread_mutexattr_settype.c: Likewise.
+	* pthread_mutex_init.c: Reject robust+pshared attribute for now.
+	Initialize mutex kind according to robust flag.
+	* pthread_mutex_lock.c: Implement local robust mutex.
+	* pthread_mutex_timedlock.c: Likewise.
+	* pthread_mutex_trylock.c: Likewise.
+	* pthread_mutex_unlock.c: Likewise.
+	* pthread_create.c (start_thread): Mark robust mutexes which remained
+	locked as dead.
+	* tst-robust1.c: New file.
+	* tst-robust2.c: New file.
+	* tst-robust3.c: New file.
+	* tst-robust4.c: New file.
+	* tst-robust5.c: New file.
+	* tst-robust6.c: New file.
+	* tst-robust7.c: New file.
+	* Makefile (libpthread-routines): Add pthread_mutexattr_getrobust,
+	pthread_mutexattr_setrobust, and pthread_mutex_consistent.
+	(tests): Add tst-robust1, tst-robust2, tst-robust3, tst-robust4,
+	tst-robust5, tst-robust6, and tst-robust7.
+
+	* tst-typesizes.c: New file.
+	* Makefile (tests): Add tst-typesizes.
+
+	* tst-once3.c: More debug output.
+
 2005-12-24  Ulrich Drepper  <drepper@redhat.com>
 
 	* pthread_mutex_trylock.c (__pthread_mutex_trylock): Add break
diff --git a/nptl/Makefile b/nptl/Makefile
index c061b9d646..ec3d00d19e 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -116,6 +116,8 @@ libpthread-routines = init vars events version \
 		      pthread_kill_other_threads \
 		      pthread_getaffinity pthread_setaffinity \
 		      pthread_attr_getaffinity pthread_attr_setaffinity \
+		      pthread_mutexattr_getrobust pthread_mutexattr_setrobust \
+		      pthread_mutex_consistent \
 		      cleanup_routine unwind-forcedunwind
 #		      pthread_setuid pthread_seteuid pthread_setreuid \
 #		      pthread_setresuid \
@@ -189,7 +191,8 @@ CFLAGS-pt-system.c = -fexceptions
 omit-deps = $(unix-syscalls:%=ptw-%)
 
 
-tests = tst-attr1 tst-attr2 tst-attr3 \
+tests = tst-typesizes \
+	tst-attr1 tst-attr2 tst-attr3 \
 	tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex5 tst-mutex6 \
 	tst-mutex7 tst-mutex8 tst-mutex9 tst-mutex5a tst-mutex7a \
 	tst-spin1 tst-spin2 tst-spin3 \
@@ -197,6 +200,8 @@ tests = tst-attr1 tst-attr2 tst-attr3 \
 	tst-cond8 tst-cond9 tst-cond10 tst-cond11 tst-cond12 tst-cond13 \
 	tst-cond14 tst-cond15 tst-cond16 tst-cond17 tst-cond18 tst-cond19 \
 	tst-cond20 tst-cond21 \
+	tst-robust1 tst-robust2 tst-robust3 tst-robust4 tst-robust5 \
+	tst-robust6 tst-robust7 \
 	tst-rwlock1 tst-rwlock2 tst-rwlock3 tst-rwlock4 tst-rwlock5 \
 	tst-rwlock6 tst-rwlock7 tst-rwlock8 tst-rwlock9 tst-rwlock10 \
 	tst-rwlock11 tst-rwlock12 tst-rwlock13 tst-rwlock14 \
diff --git a/nptl/Versions b/nptl/Versions
index 79bf190c3a..2b4dd01ab5 100644
--- a/nptl/Versions
+++ b/nptl/Versions
@@ -232,6 +232,11 @@ libpthread {
     pthread_setschedprio;
   }
 
+  GLIBC_2.4 {
+    pthread_mutexattr_getrobust_np; pthread_mutexattr_setrobust_np;
+    pthread_mutex_consistent_np;
+  };
+
   GLIBC_PRIVATE {
     __pthread_initialize_minimal;
     __pthread_clock_gettime; __pthread_clock_settime;
diff --git a/nptl/descr.h b/nptl/descr.h
index aaef9bc621..a9f830ef0b 100644
--- a/nptl/descr.h
+++ b/nptl/descr.h
@@ -134,6 +134,51 @@ struct pthread
   /* Process ID - thread group ID in kernel speak.  */
   pid_t pid;
 
+  /* List of robust mutexes the thread is holding.  */
+  pthread_mutex_t *robust_list;
+
+#ifdef __PTHREAD_MUTEX_HAVE_PREV
+# define ENQUEUE_MUTEX(mutex) \
+  do {									      \
+    mutex->__data.__next = THREAD_GETMEM (THREAD_SELF, robust_list);	      \
+    THREAD_SETMEM (THREAD_SELF, robust_list, mutex);			      \
+    if (mutex->__data.__next != NULL)					      \
+      mutex->__data.__next->__data.__prev = mutex;			      \
+    mutex->__data.__prev = NULL;					      \
+  } while (0)
+# define DEQUEUE_MUTEX(mutex) \
+  do {									      \
+    if (mutex->__data.__prev == NULL)					      \
+      THREAD_SETMEM (THREAD_SELF, robust_list, mutex->__data.__next);	      \
+    else								      \
+      mutex->__data.__prev->__data.__next = mutex->__data.__next;	      \
+    if (mutex->__data.__next != NULL)					      \
+      mutex->__data.__next->__data.__prev = mutex->__data.__prev;	      \
+    mutex->__data.__prev = NULL;					      \
+    mutex->__data.__next = NULL;					      \
+  } while (0)
+#else
+# define ENQUEUE_MUTEX(mutex) \
+  do {									      \
+    mutex->__data.__next = THREAD_GETMEM (THREAD_SELF, robust_list);	      \
+    THREAD_SETMEM (THREAD_SELF, robust_list, mutex);			      \
+  } while (0)
+# define DEQUEUE_MUTEX(mutex) \
+  do {									      \
+    pthread_mutex_t *runp = THREAD_GETMEM (THREAD_SELF, robust_list);	      \
+    if (runp == mutex)							      \
+      THREAD_SETMEM (THREAD_SELF, robust_list, runp->__data.__next);	      \
+    else								      \
+      {									      \
+	while (runp->__data.__next != mutex)				      \
+	  runp = runp->__data.__next;					      \
+									      \
+	runp->__data.__next = runp->__data.__next->__data.__next;	      \
+	mutex->__data.__next = NULL;					      \
+      }									      \
+  } while (0)
+#endif
+
   /* List of cleanup buffers.  */
   struct _pthread_cleanup_buffer *cleanup;
 
diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
index 24168146fa..61b7176159 100644
--- a/nptl/pthreadP.h
+++ b/nptl/pthreadP.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -51,6 +51,32 @@
 #endif
 
 
+/* Magic cookie representing robust mutex with dead owner.  */
+#define PTHREAD_MUTEX_OWNERDEAD		INT_MAX
+/* Magic cookie representing not recoverable robust mutex.  */
+#define PTHREAD_MUTEX_NOTRECOVERABLE	(INT_MAX - 1)
+
+
+/* Internal mutex type value.  */
+enum
+{
+  PTHREAD_MUTEX_ROBUST_PRIVATE_NP = 256,
+  PTHREAD_MUTEX_ROBUST_PRIVATE_RECURSIVE_NP
+  = PTHREAD_MUTEX_ROBUST_PRIVATE_NP | PTHREAD_MUTEX_RECURSIVE_NP,
+  PTHREAD_MUTEX_ROBUST_PRIVATE_ERRORCHECK_NP
+  = PTHREAD_MUTEX_ROBUST_PRIVATE_NP | PTHREAD_MUTEX_ERRORCHECK_NP,
+  PTHREAD_MUTEX_ROBUST_PRIVATE_ADAPTIVE_NP
+  = PTHREAD_MUTEX_ROBUST_PRIVATE_NP | PTHREAD_MUTEX_ADAPTIVE_NP
+};
+
+
+/* Flags in mutex attr.  */
+#define PTHREAD_MUTEXATTR_FLAG_ROBUST	0x40000000
+#define PTHREAD_MUTEXATTR_FLAG_PSHARED	0x80000000
+#define PTHREAD_MUTEXATTR_FLAG_BITS \
+  (PTHREAD_MUTEXATTR_FLAG_ROBUST | PTHREAD_MUTEXATTR_FLAG_PSHARED)
+
+
 /* Internal variables.  */
 
 
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
index 729b76b838..2dbe58dcd4 100644
--- a/nptl/pthread_create.c
+++ b/nptl/pthread_create.c
@@ -310,6 +310,33 @@ start_thread (void *arg)
      the breakpoint reports TD_THR_RUN state rather than TD_THR_ZOMBIE.  */
   atomic_bit_set (&pd->cancelhandling, EXITING_BIT);
 
+  /* If this thread has any robust mutexes locked, handle them now.  */
+  pthread_mutex_t *robust = THREAD_GETMEM (pd, robust_list);
+  if (__builtin_expect (robust != NULL, 0))
+    {
+      do
+	{
+	  pthread_mutex_t *this = robust;
+	  robust = robust->__data.__next;
+
+	  assert (lll_mutex_islocked (this->__data.__lock));
+	  this->__data.__count = 0;
+	  --this->__data.__nusers;
+	  assert (this->__data.__owner != PTHREAD_MUTEX_NOTRECOVERABLE);
+	  this->__data.__owner = PTHREAD_MUTEX_OWNERDEAD;
+	  this->__data.__next = NULL;
+#ifdef __PTHREAD_MUTEX_HAVE_PREV
+	  this->__data.__prev = NULL;
+#endif
+
+	  lll_mutex_unlock (this->__data.__lock);
+	}
+      while (robust != NULL);
+
+      /* Clean up so that the thread descriptor can be reused.  */
+      THREAD_SETMEM (pd, robust_list, NULL);
+    }
+
   /* If the thread is detached free the TCB.  */
   if (IS_DETACHED (pd))
     /* Free the TCB.  */
diff --git a/nptl/pthread_mutex_consistent.c b/nptl/pthread_mutex_consistent.c
new file mode 100644
index 0000000000..2edfe8a5a6
--- /dev/null
+++ b/nptl/pthread_mutex_consistent.c
@@ -0,0 +1,36 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthreadP.h>
+
+
+int
+pthread_mutex_consistent_np (mutex)
+     pthread_mutex_t *mutex;
+{
+  /* Test whether this is a robust mutex with a dead owner.  */
+  if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_PRIVATE_NP) == 0
+      || mutex->__data.__owner != -THREAD_GETMEM (THREAD_SELF, tid))
+    return EINVAL;
+
+  mutex->__data.__owner = -mutex->__data.__owner;
+
+  return 0;
+}
diff --git a/nptl/pthread_mutex_init.c b/nptl/pthread_mutex_init.c
index 074941daf3..17d1c99575 100644
--- a/nptl/pthread_mutex_init.c
+++ b/nptl/pthread_mutex_init.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -18,6 +18,7 @@
    02111-1307 USA.  */
 
 #include <assert.h>
+#include <errno.h>
 #include <string.h>
 #include "pthreadP.h"
 
@@ -40,17 +41,26 @@ __pthread_mutex_init (mutex, mutexattr)
 
   imutexattr = (const struct pthread_mutexattr *) mutexattr ?: &default_attr;
 
+  /* Sanity checks.  */
+  // XXX For now we cannot implement robust mutexes if they are shared.
+  if ((imutexattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_ROBUST) != 0
+      && (imutexattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_PSHARED) != 0)
+    return ENOTSUP;
+
   /* Clear the whole variable.  */
   memset (mutex, '\0', __SIZEOF_PTHREAD_MUTEX_T);
 
   /* Copy the values from the attribute.  */
-  mutex->__data.__kind = imutexattr->mutexkind & ~0x80000000;
+  mutex->__data.__kind = imutexattr->mutexkind & ~PTHREAD_MUTEXATTR_FLAG_BITS;
+  if ((imutexattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_ROBUST) != 0)
+    mutex->__data.__kind |= PTHREAD_MUTEX_ROBUST_PRIVATE_NP;
 
   /* Default values: mutex not used yet.  */
   // mutex->__count = 0;	already done by memset
   // mutex->__owner = 0;	already done by memset
   // mutex->__nusers = 0;	already done by memset
   // mutex->__spins = 0;	already done by memset
+  // mutex->__next = NULL;	already done by memset
 
   return 0;
 }
diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c
index a2d0afbe15..420711a4d4 100644
--- a/nptl/pthread_mutex_lock.c
+++ b/nptl/pthread_mutex_lock.c
@@ -19,6 +19,7 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <stdlib.h>
 #include "pthreadP.h"
 #include <lowlevellock.h>
 
@@ -37,6 +38,7 @@ __pthread_mutex_lock (mutex)
 
   pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
 
+  int retval = 0;
   switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP))
     {
       /* Recursive mutex.  */
@@ -57,13 +59,14 @@ __pthread_mutex_lock (mutex)
       /* We have to get the mutex.  */
       LLL_MUTEX_LOCK (mutex->__data.__lock);
 
+      assert (mutex->__data.__owner == 0);
       mutex->__data.__count = 1;
       break;
 
       /* Error checking mutex.  */
     case PTHREAD_MUTEX_ERRORCHECK_NP:
       /* Check whether we already hold the mutex.  */
-      if (mutex->__data.__owner == id)
+      if (__builtin_expect (mutex->__data.__owner == id, 0))
 	return EDEADLK;
 
       /* FALLTHROUGH */
@@ -72,6 +75,7 @@ __pthread_mutex_lock (mutex)
     simple:
       /* Normal mutex.  */
       LLL_MUTEX_LOCK (mutex->__data.__lock);
+      assert (mutex->__data.__owner == 0);
       break;
 
     case PTHREAD_MUTEX_ADAPTIVE_NP:
@@ -99,6 +103,65 @@ __pthread_mutex_lock (mutex)
 
 	  mutex->__data.__spins += (cnt - mutex->__data.__spins) / 8;
 	}
+      assert (mutex->__data.__owner == 0);
+      break;
+
+    case PTHREAD_MUTEX_ROBUST_PRIVATE_RECURSIVE_NP:
+      /* Check whether we already hold the mutex.  */
+      if (abs (mutex->__data.__owner) == id)
+	{
+	  /* Just bump the counter.  */
+	  if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
+	    /* Overflow of the counter.  */
+	    return EAGAIN;
+
+	  ++mutex->__data.__count;
+
+	  return 0;
+	}
+
+      /* We have to get the mutex.  */
+      LLL_MUTEX_LOCK (mutex->__data.__lock);
+
+      mutex->__data.__count = 1;
+
+      goto robust;
+
+    case PTHREAD_MUTEX_ROBUST_PRIVATE_ERRORCHECK_NP:
+      /* Check whether we already hold the mutex.  */
+      if (__builtin_expect (abs (mutex->__data.__owner) == id, 0))
+	return EDEADLK;
+
+      /* FALLTHROUGH */
+
+    case PTHREAD_MUTEX_ROBUST_PRIVATE_NP:
+    case PTHREAD_MUTEX_ROBUST_PRIVATE_ADAPTIVE_NP:
+      LLL_MUTEX_LOCK (mutex->__data.__lock);
+
+    robust:
+      if (__builtin_expect (mutex->__data.__owner
+			    == PTHREAD_MUTEX_NOTRECOVERABLE, 0))
+	{
+	  /* This mutex is now not recoverable.  */
+	  mutex->__data.__count = 0;
+	  lll_mutex_unlock (mutex->__data.__lock);
+	  return ENOTRECOVERABLE;
+	}
+
+      /* This mutex is either healthy or we can try to recover it.  */
+      assert (mutex->__data.__owner == 0
+	      || mutex->__data.__owner == PTHREAD_MUTEX_OWNERDEAD);
+
+      if (__builtin_expect (mutex->__data.__owner
+			    == PTHREAD_MUTEX_OWNERDEAD, 0))
+	{
+	  retval = EOWNERDEAD;
+	  /* We signal ownership of a not yet recovered robust mutex
+	     by storing the negative thread ID.  */
+	  id = -id;
+	}
+
+      ENQUEUE_MUTEX (mutex);
       break;
 
     default:
@@ -107,13 +170,12 @@ __pthread_mutex_lock (mutex)
     }
 
   /* Record the ownership.  */
-  assert (mutex->__data.__owner == 0);
   mutex->__data.__owner = id;
 #ifndef NO_INCR
   ++mutex->__data.__nusers;
 #endif
 
-  return 0;
+  return retval;
 }
 #ifndef __pthread_mutex_lock
 strong_alias (__pthread_mutex_lock, pthread_mutex_lock)
diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c
index 06bdf9d1cc..bc4ead765d 100644
--- a/nptl/pthread_mutex_timedlock.c
+++ b/nptl/pthread_mutex_timedlock.c
@@ -17,6 +17,7 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
+#include <assert.h>
 #include <errno.h>
 #include "pthreadP.h"
 #include <lowlevellock.h>
@@ -49,17 +50,15 @@ pthread_mutex_timedlock (mutex, abstime)
 
 	  goto out;
 	}
-      else
-	{
-	  /* We have to get the mutex.  */
-	  result = lll_mutex_timedlock (mutex->__data.__lock, abstime);
 
-	  if (result != 0)
-	    goto out;
+      /* We have to get the mutex.  */
+      result = lll_mutex_timedlock (mutex->__data.__lock, abstime);
 
-	  /* Only locked once so far.  */
-	  mutex->__data.__count = 1;
-	}
+      if (result != 0)
+	goto out;
+
+      /* Only locked once so far.  */
+      mutex->__data.__count = 1;
       break;
 
       /* Error checking mutex.  */
@@ -103,6 +102,71 @@ pthread_mutex_timedlock (mutex, abstime)
 	}
       break;
 
+    case PTHREAD_MUTEX_ROBUST_PRIVATE_RECURSIVE_NP:
+      /* Check whether we already hold the mutex.  */
+      if (abs (mutex->__data.__owner) == id)
+	{
+	  /* Just bump the counter.  */
+	  if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
+	    /* Overflow of the counter.  */
+	    return EAGAIN;
+
+	  ++mutex->__data.__count;
+
+	  goto out;
+	}
+
+      /* We have to get the mutex.  */
+      result = lll_mutex_timedlock (mutex->__data.__lock, abstime);
+
+      if (result != 0)
+	goto out;
+
+      /* Only locked once so far.  */
+      mutex->__data.__count = 1;
+      goto robust;
+
+    case PTHREAD_MUTEX_ROBUST_PRIVATE_ERRORCHECK_NP:
+      /* Check whether we already hold the mutex.  */
+      if (__builtin_expect (abs (mutex->__data.__owner) == id, 0))
+	return EDEADLK;
+
+      /* FALLTHROUGH */
+
+    case PTHREAD_MUTEX_ROBUST_PRIVATE_NP:
+    case PTHREAD_MUTEX_ROBUST_PRIVATE_ADAPTIVE_NP:
+      result = lll_mutex_timedlock (mutex->__data.__lock, abstime);
+
+      if (result != 0)
+	goto out;
+
+    robust:
+      if (__builtin_expect (mutex->__data.__owner
+			    == PTHREAD_MUTEX_NOTRECOVERABLE, 0))
+	{
+	  /* This mutex is now not recoverable.  */
+	  mutex->__data.__count = 0;
+	  lll_mutex_unlock (mutex->__data.__lock);
+	  return ENOTRECOVERABLE;
+	}
+
+      /* This mutex is either healthy or we can try to recover it.  */
+      assert (mutex->__data.__owner == 0
+	      || mutex->__data.__owner == PTHREAD_MUTEX_OWNERDEAD);
+
+      if (__builtin_expect (mutex->__data.__owner
+			    == PTHREAD_MUTEX_OWNERDEAD, 0))
+	{
+	  result = EOWNERDEAD;
+	  /* We signal ownership of a not yet recovered robust mutex
+	     by storing the negative thread ID.  */
+	  mutex->__data.__owner = -id;
+	  ++mutex->__data.__nusers;
+	}
+
+      ENQUEUE_MUTEX (mutex);
+      break;
+
     default:
       /* Correct code cannot set any other type.  */
       return EINVAL;
diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c
index 8213f90da9..ae73ecc39b 100644
--- a/nptl/pthread_mutex_trylock.c
+++ b/nptl/pthread_mutex_trylock.c
@@ -17,7 +17,9 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
+#include <assert.h>
 #include <errno.h>
+#include <stdlib.h>
 #include "pthreadP.h"
 #include <lowlevellock.h>
 
@@ -26,13 +28,12 @@ int
 __pthread_mutex_trylock (mutex)
      pthread_mutex_t *mutex;
 {
-  pid_t id;
+  pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
 
   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)
 	{
@@ -56,20 +57,93 @@ __pthread_mutex_trylock (mutex)
       break;
 
     case PTHREAD_MUTEX_ERRORCHECK_NP:
-      /* Error checking mutex.  We do not check for deadlocks.  */
+      /* Check whether we already hold the mutex.  */
+      if (__builtin_expect (mutex->__data.__owner == id, 0))
+	return EDEADLK;
+
+      /* FALLTHROUGH */
+
     case PTHREAD_MUTEX_TIMED_NP:
     case PTHREAD_MUTEX_ADAPTIVE_NP:
       /* Normal mutex.  */
-      if (lll_mutex_trylock (mutex->__data.__lock) == 0)
+      if (lll_mutex_trylock (mutex->__data.__lock) != 0)
+	break;
+
+      /* Record the ownership.  */
+      mutex->__data.__owner = id;
+      ++mutex->__data.__nusers;
+
+      return 0;
+
+
+    case PTHREAD_MUTEX_ROBUST_PRIVATE_RECURSIVE_NP:
+      /* Check whether we already hold the mutex.  */
+      if (abs (mutex->__data.__owner) == id)
 	{
-	  /* Record the ownership.  */
-	  mutex->__data.__owner = THREAD_GETMEM (THREAD_SELF, tid);
-	  ++mutex->__data.__nusers;
+	  /* Just bump the counter.  */
+	  if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
+	    /* Overflow of the counter.  */
+	    return EAGAIN;
+
+	  ++mutex->__data.__count;
 
 	  return 0;
 	}
+
+      /* We have to get the mutex.  */
+      if (lll_mutex_trylock (mutex->__data.__lock) == 0)
+	{
+	  mutex->__data.__count = 1;
+
+	  goto robust;
+	}
+
       break;
 
+    case PTHREAD_MUTEX_ROBUST_PRIVATE_ERRORCHECK_NP:
+      /* Check whether we already hold the mutex.  */
+      if (__builtin_expect (abs (mutex->__data.__owner) == id, 0))
+	return EDEADLK;
+
+      /* FALLTHROUGH */
+
+    case PTHREAD_MUTEX_ROBUST_PRIVATE_NP:
+    case PTHREAD_MUTEX_ROBUST_PRIVATE_ADAPTIVE_NP:
+      if (lll_mutex_trylock (mutex->__data.__lock) != 0)
+	break;
+
+    robust:
+      if (__builtin_expect (mutex->__data.__owner
+			    == PTHREAD_MUTEX_NOTRECOVERABLE, 0))
+	{
+	  /* This mutex is now not recoverable.  */
+	  mutex->__data.__count = 0;
+	  lll_mutex_unlock (mutex->__data.__lock);
+	  return ENOTRECOVERABLE;
+	}
+
+      /* This mutex is either healthy or we can try to recover it.  */
+      assert (mutex->__data.__owner == 0
+	      || mutex->__data.__owner == PTHREAD_MUTEX_OWNERDEAD);
+
+      /* Record the ownership.  */
+      int retval = 0;
+      if (__builtin_expect (mutex->__data.__owner
+			    == PTHREAD_MUTEX_OWNERDEAD, 0))
+	{
+	  retval = EOWNERDEAD;
+	  /* We signal ownership of a not yet recovered robust
+	     mutex by storing the negative thread ID.  */
+	  id = -id;
+	}
+
+      ENQUEUE_MUTEX (mutex);
+
+      mutex->__data.__owner = id;
+      ++mutex->__data.__nusers;
+
+      return retval
+;
     default:
       /* Correct code cannot set any other type.  */
       return EINVAL;
diff --git a/nptl/pthread_mutex_unlock.c b/nptl/pthread_mutex_unlock.c
index 5f097a596d..babce51a6f 100644
--- a/nptl/pthread_mutex_unlock.c
+++ b/nptl/pthread_mutex_unlock.c
@@ -18,6 +18,7 @@
    02111-1307 USA.  */
 
 #include <errno.h>
+#include <stdlib.h>
 #include "pthreadP.h"
 #include <lowlevellock.h>
 
@@ -28,6 +29,8 @@ __pthread_mutex_unlock_usercnt (mutex, decr)
      pthread_mutex_t *mutex;
      int decr;
 {
+  int newowner = 0;
+
   switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP))
     {
     case PTHREAD_MUTEX_RECURSIVE_NP:
@@ -52,13 +55,58 @@ __pthread_mutex_unlock_usercnt (mutex, decr)
       /* Normal mutex.  Nothing special to do.  */
       break;
 
+    case PTHREAD_MUTEX_ROBUST_PRIVATE_RECURSIVE_NP:
+      /* Recursive mutex.  */
+      if (mutex->__data.__owner == -THREAD_GETMEM (THREAD_SELF, tid))
+	{
+	  if (--mutex->__data.__count != 0)
+	    /* We still hold the mutex.  */
+	    return ENOTRECOVERABLE;
+
+	  goto notrecoverable;
+	}
+
+      if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
+	return EPERM;
+
+      if (--mutex->__data.__count != 0)
+	/* We still hold the mutex.  */
+	return 0;
+
+      goto robust;
+
+    case PTHREAD_MUTEX_ROBUST_PRIVATE_ERRORCHECK_NP:
+      /* Error checking mutex.  */
+      if (abs (mutex->__data.__owner) != THREAD_GETMEM (THREAD_SELF, tid)
+	  || ! lll_mutex_islocked (mutex->__data.__lock))
+	return EPERM;
+
+      /* FALLTHROUGH */
+
+    case PTHREAD_MUTEX_ROBUST_PRIVATE_NP:
+    case PTHREAD_MUTEX_ROBUST_PRIVATE_ADAPTIVE_NP:
+      /* If the previous owner died and the caller did not succeed in
+	 making the state consistent, mark the mutex as unrecoverable
+	 and make all waiters.  */
+      if (__builtin_expect (mutex->__data.__owner
+			    == -THREAD_GETMEM (THREAD_SELF, tid)
+			    || (mutex->__data.__owner
+				== PTHREAD_MUTEX_NOTRECOVERABLE), 0))
+      notrecoverable:
+	newowner = PTHREAD_MUTEX_NOTRECOVERABLE;
+
+    robust:
+      /* Remove mutex from the list.  */
+      DEQUEUE_MUTEX (mutex);
+      break;
+
     default:
       /* Correct code cannot set any other type.  */
       return EINVAL;
     }
 
   /* Always reset the owner field.  */
-  mutex->__data.__owner = 0;
+  mutex->__data.__owner = newowner;
   if (decr)
     /* One less user.  */
     --mutex->__data.__nusers;
diff --git a/nptl/pthread_mutexattr_getpshared.c b/nptl/pthread_mutexattr_getpshared.c
index 4bd4ea18db..6454125db2 100644
--- a/nptl/pthread_mutexattr_getpshared.c
+++ b/nptl/pthread_mutexattr_getpshared.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2005 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -29,9 +29,7 @@ pthread_mutexattr_getpshared (attr, pshared)
 
   iattr = (const struct pthread_mutexattr *) attr;
 
-  /* We use bit 31 to signal whether the mutex is going to be
-     process-shared or not.  */
-  *pshared = ((iattr->mutexkind & 0x80000000) != 0
+  *pshared = ((iattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_PSHARED) != 0
 	      ? PTHREAD_PROCESS_SHARED : PTHREAD_PROCESS_PRIVATE);
 
   return 0;
diff --git a/nptl/pthread_mutexattr_getrobust.c b/nptl/pthread_mutexattr_getrobust.c
new file mode 100644
index 0000000000..5ec43d1f7c
--- /dev/null
+++ b/nptl/pthread_mutexattr_getrobust.c
@@ -0,0 +1,36 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthreadP.h>
+
+
+int
+pthread_mutexattr_getrobust_np (attr, robustness)
+     const pthread_mutexattr_t *attr;
+     int *robustness;
+{
+  const struct pthread_mutexattr *iattr;
+
+  iattr = (const struct pthread_mutexattr *) attr;
+
+  *robustness = ((iattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_ROBUST) != 0
+		 ? PTHREAD_MUTEX_ROBUST_NP : PTHREAD_MUTEX_STALLED_NP);
+
+  return 0;
+}
diff --git a/nptl/pthread_mutexattr_gettype.c b/nptl/pthread_mutexattr_gettype.c
index 5c32b2c6f1..7303703bf4 100644
--- a/nptl/pthread_mutexattr_gettype.c
+++ b/nptl/pthread_mutexattr_gettype.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2005 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -29,9 +29,7 @@ pthread_mutexattr_gettype (attr, kind)
 
   iattr = (const struct pthread_mutexattr *) attr;
 
-  /* We use bit 31 to signal whether the mutex is going to be
-     process-shared or not.  */
-  *kind = iattr->mutexkind & ~0x80000000;
+  *kind = iattr->mutexkind & ~PTHREAD_MUTEXATTR_FLAG_BITS;
 
   return 0;
 }
diff --git a/nptl/pthread_mutexattr_setpshared.c b/nptl/pthread_mutexattr_setpshared.c
index 5f2cf417e3..8e08b9e161 100644
--- a/nptl/pthread_mutexattr_setpshared.c
+++ b/nptl/pthread_mutexattr_setpshared.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2005 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -34,12 +34,10 @@ pthread_mutexattr_setpshared (attr, pshared)
 
   iattr = (struct pthread_mutexattr *) attr;
 
-  /* We use bit 31 to signal whether the mutex is going to be
-     process-shared or not.  */
   if (pshared == PTHREAD_PROCESS_PRIVATE)
-    iattr->mutexkind &= ~0x80000000;
+    iattr->mutexkind &= ~PTHREAD_MUTEXATTR_FLAG_PSHARED;
   else
-    iattr->mutexkind |= 0x80000000;
+    iattr->mutexkind |= PTHREAD_MUTEXATTR_FLAG_PSHARED;
 
   return 0;
 }
diff --git a/nptl/pthread_mutexattr_setrobust.c b/nptl/pthread_mutexattr_setrobust.c
new file mode 100644
index 0000000000..cf95e35b6f
--- /dev/null
+++ b/nptl/pthread_mutexattr_setrobust.c
@@ -0,0 +1,43 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthreadP.h>
+
+
+int
+pthread_mutexattr_setrobust_np (attr, robustness)
+     pthread_mutexattr_t *attr;
+     int robustness;
+{
+  if (robustness != PTHREAD_MUTEX_STALLED_NP
+      && __builtin_expect (robustness != PTHREAD_MUTEX_ROBUST_NP, 0))
+    return EINVAL;
+
+  struct pthread_mutexattr *iattr = (struct pthread_mutexattr *) attr;
+
+  /* We use bit 30 to signal whether the mutex is going to be
+     robust or not.  */
+  if (robustness == PTHREAD_MUTEX_STALLED_NP)
+    iattr->mutexkind &= ~PTHREAD_MUTEXATTR_FLAG_ROBUST;
+  else
+    iattr->mutexkind |= PTHREAD_MUTEXATTR_FLAG_ROBUST;
+
+  return 0;
+}
diff --git a/nptl/pthread_mutexattr_settype.c b/nptl/pthread_mutexattr_settype.c
index c77fe79df5..fe6b5c22cd 100644
--- a/nptl/pthread_mutexattr_settype.c
+++ b/nptl/pthread_mutexattr_settype.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2005 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -33,9 +33,7 @@ __pthread_mutexattr_settype (attr, kind)
 
   iattr = (struct pthread_mutexattr *) attr;
 
-  /* We use bit 31 to signal whether the mutex is going to be
-     process-shared or not.  */
-  iattr->mutexkind = (iattr->mutexkind & 0x80000000) | kind;
+  iattr->mutexkind = (iattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_BITS) | kind;
 
   return 0;
 }
diff --git a/nptl/sysdeps/pthread/pthread.h b/nptl/sysdeps/pthread/pthread.h
index badadae169..5413661eb3 100644
--- a/nptl/sysdeps/pthread/pthread.h
+++ b/nptl/sysdeps/pthread/pthread.h
@@ -60,24 +60,39 @@ enum
 #endif
 };
 
-/* Mutex initializers.  */
-#define PTHREAD_MUTEX_INITIALIZER \
-  { { 0, 0, 0, 0, 0, 0 } }
+
 #ifdef __USE_GNU
-# if __WORDSIZE == 64
+/* Robust mutex or not flags.  */
+enum
+{
+  PTHREAD_MUTEX_STALLED_NP,
+  PTHREAD_MUTEX_ROBUST_NP
+};
+#endif
+
+
+/* Mutex initializers.  */
+#if __WORDSIZE == 64
+# define PTHREAD_MUTEX_INITIALIZER \
+  { { 0, 0, 0, 0, 0, 0, (void *) 0, (void *) 0 } }
+# ifdef __USE_GNU
 #  define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \
-  { { 0, 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, 0 } }
+  { { 0, 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, 0, (void *) 0, (void *) 0 } }
 #  define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \
-  { { 0, 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, 0 } }
+  { { 0, 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, 0, (void *) 0, (void *) 0 } }
 #  define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \
-  { { 0, 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, 0 } }
-# else
+  { { 0, 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, 0, (void *) 0, (void *) 0 } }
+# endif
+#else
+# define PTHREAD_MUTEX_INITIALIZER \
+  { { 0, 0, 0, 0, 0, { 0 } } }
+# ifdef __USE_GNU
 #  define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \
-  { { 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, 0, 0 } }
+  { { 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, 0, { 0 } } }
 #  define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \
-  { { 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, 0, 0 } }
+  { { 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, 0, { 0 } } }
 #  define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \
-  { { 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, 0, 0 } }
+  { { 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, 0, { 0 } } }
 # endif
 #endif
 
@@ -696,6 +711,12 @@ extern int pthread_mutex_timedlock (pthread_mutex_t *__restrict __mutex,
 extern int pthread_mutex_unlock (pthread_mutex_t *__mutex) __THROW;
 
 
+#ifdef __USE_GNU
+/* Declare the state protected by MUTEX as consistent.  */
+extern int pthread_mutex_consistent_np (pthread_mutex_t *__mutex) __THROW;
+#endif
+
+
 /* Functions for handling mutex attributes.  */
 
 /* Initialize mutex attribute object ATTR with default attributes
@@ -726,6 +747,16 @@ extern int pthread_mutexattr_settype (pthread_mutexattr_t *__attr, int __kind)
      __THROW;
 #endif
 
+#ifdef __USE_GNU
+/* Get the robustness flag of the mutex attribute ATTR.  */
+extern int pthread_mutexattr_getrobust_np (__const pthread_mutexattr_t *__attr,
+					   int *__robustness) __THROW;
+
+/* Set the robustness flag of the mutex attribute ATTR.  */
+extern int pthread_mutexattr_setrobust_np (pthread_mutexattr_t *__attr,
+					   int __robustness) __THROW;
+#endif
+
 
 #if defined __USE_UNIX98 || defined __USE_XOPEN2K
 /* Functions for handling read-write locks.  */
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
index ddb3574aaa..3bd1019995 100644
--- a/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
@@ -45,7 +45,7 @@ typedef union
 
 /* Data structures for mutex handling.  The structure of the attribute
    type is not exposed on purpose.  */
-typedef union
+typedef union __pthread_mutex_u
 {
   struct
   {
@@ -56,7 +56,11 @@ typedef union
        binary compatibility.  */
     int __kind;
     unsigned int __nusers;
-    int __spins;
+    union
+    {
+      int __spins;
+      union __pthread_mutex_u *__next;
+    };
   } __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 7f1ace693c..3eb33a8646 100644
--- a/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h
@@ -59,7 +59,7 @@ typedef union
 
 /* Data structures for mutex handling.  The structure of the attribute
    type is not exposed on purpose.  */
-typedef union
+typedef union __pthread_mutex_u
 {
   struct
   {
@@ -72,10 +72,19 @@ typedef union
     /* KIND must stay at this position in the structure to maintain
        binary compatibility.  */
     int __kind;
-#if __WORDSIZE != 64
+#if __WORDSIZE == 64
+    int __spins;
+    union __pthread_mutex_u *__next;
+    union __pthread_mutex_u *__prev;
+# define __PTHREAD_MUTEX_HAVE_PREV	1
+#else
     unsigned int __nusers;
+    union
+    {
+      int __spins;
+      union __pthread_mutex_u *__next;
+    };
 #endif
-    int __spins;
   } __data;
   char __size[__SIZEOF_PTHREAD_MUTEX_T];
   long int __align;
diff --git a/nptl/tst-once3.c b/nptl/tst-once3.c
index 43b354a391..1a74abb530 100644
--- a/nptl/tst-once3.c
+++ b/nptl/tst-once3.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -52,6 +52,8 @@ once_handler1 (void)
       exit (1);
     }
 
+  puts ("once_handler1: going to wait on cond");
+
   pthread_cond_wait (&cond, &mut);
 
   /* We should never get here.  */
@@ -139,6 +141,9 @@ do_test (void)
       puts ("join didn't return PTHREAD_CANCELED");
       return 1;
     }
+  puts ("joined successfully");
+
+  printf ("once = %d\n", *(int *) &once);
 
   if (cl_called != 1)
     {
diff --git a/nptl/tst-robust1.c b/nptl/tst-robust1.c
new file mode 100644
index 0000000000..13267a5efd
--- /dev/null
+++ b/nptl/tst-robust1.c
@@ -0,0 +1,245 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+   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 <stdlib.h>
+
+
+static pthread_mutex_t m;
+static pthread_barrier_t b;
+
+
+#ifndef LOCK
+# define LOCK(m) pthread_mutex_lock (m)
+#endif
+
+
+static void *
+tf (void *arg)
+{
+  long int round = (long int) arg;
+
+  if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) != 0)
+    {
+      printf ("%ld: setcancelstate failed\n", round);
+      exit (1);
+    }
+
+  int e = LOCK (&m);
+  if (e != 0)
+    {
+      printf ("%ld: child: mutex_lock failed with error %d\n", round, e);
+      exit (1);
+    }
+
+  e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%ld: child: 1st barrier_wait failed\n", round);
+      exit (1);
+    }
+
+  e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%ld: child: 2nd barrier_wait failed\n", round);
+      exit (1);
+    }
+
+  pthread_testcancel ();
+
+  printf ("%ld: testcancel returned\n", round);
+  exit (1);
+}
+
+
+static int
+do_test (void)
+{
+#ifdef PREPARE_TMO
+  PREPARE_TMO;
+#endif
+
+  pthread_mutexattr_t a;
+  if (pthread_mutexattr_init (&a) != 0)
+    {
+      puts ("mutexattr_init failed");
+      return 1;
+    }
+  if (pthread_mutexattr_setrobust_np (&a, PTHREAD_MUTEX_ROBUST_NP) != 0)
+    {
+      puts ("mutexattr_setrobust failed");
+      return 1;
+    }
+#ifndef NOT_CONSISTENT
+  if (pthread_mutex_init (&m, &a) != 0)
+    {
+      puts ("mutex_init failed");
+      return 1;
+    }
+#endif
+
+  if (pthread_barrier_init (&b, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  for (long int round = 1; round < 5; ++round)
+    {
+#ifdef NOT_CONSISTENT
+      if (pthread_mutex_init (&m, &a) != 0)
+	{
+	  puts ("mutex_init failed");
+	  return 1;
+	}
+#endif
+
+      pthread_t th;
+      if (pthread_create (&th, NULL, tf, (void *) round) != 0)
+	{
+	  printf ("%ld: create failed\n", round);
+	  return 1;
+	}
+
+      int e = pthread_barrier_wait (&b);
+      if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%ld: parent: 1st barrier_wait failed\n", round);
+	  return 1;
+	}
+
+      if (pthread_cancel (th) != 0)
+	{
+	  printf ("%ld: cancel failed\n", round);
+	  return 1;
+	}
+
+      e = pthread_barrier_wait (&b);
+      if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%ld: parent: 2nd barrier_wait failed\n", round);
+	  return 1;
+	}
+
+#ifndef AFTER_JOIN
+      if (round & 1)
+#endif
+	{
+	  void *res;
+	  if (pthread_join (th, &res) != 0)
+	    {
+	      printf ("%ld: join failed\n", round);
+	      return 1;
+	    }
+	  if (res != PTHREAD_CANCELED)
+	    {
+	      printf ("%ld: thread not canceled\n", round);
+	      return 1;
+	    }
+	}
+
+      e = LOCK (&m);
+      if (e == 0)
+	{
+	  printf ("%ld: parent: mutex_lock succeeded\n", round);
+	  return 1;
+	}
+      if (e != EOWNERDEAD)
+	{
+	  printf ("%ld: parent: mutex_lock returned wrong code\n", round);
+	  return 1;
+	}
+
+#ifndef AFTER_JOIN
+      if ((round & 1) == 0)
+	{
+	  void *res;
+	  if (pthread_join (th, &res) != 0)
+	    {
+	      printf ("%ld: join failed\n", round);
+	      return 1;
+	    }
+	  if (res != PTHREAD_CANCELED)
+	    {
+	      printf ("%ld: thread not canceled\n", round);
+	      return 1;
+	    }
+	}
+#endif
+
+#ifndef NOT_CONSISTENT
+      e = pthread_mutex_consistent_np (&m);
+      if (e != 0)
+	{
+	  printf ("%ld: mutex_consistent failed with error %d\n", round, e);
+	  return 1;
+	}
+#endif
+
+      e = pthread_mutex_unlock (&m);
+      if (e != 0)
+	{
+	  printf ("%ld: mutex_unlocked failed\n", round);
+	  return 1;
+	}
+
+#ifdef NOT_CONSISTENT
+      e = LOCK (&m);
+      if (e == 0)
+	{
+	  printf ("%ld: locking inconsistent mutex succeeded\n", round);
+	  return 1;
+	}
+      if (e != ENOTRECOVERABLE)
+	{
+	  printf ("%ld: locking inconsistent mutex failed with error %d\n",
+		  round, e);
+	  return 1;
+	}
+
+      if (pthread_mutex_destroy (&m) != 0)
+	{
+	  puts ("mutex_destroy failed");
+	  return 1;
+	}
+#endif
+    }
+
+#ifndef NOT_CONSISTENT
+  if (pthread_mutex_destroy (&m) != 0)
+    {
+      puts ("mutex_destroy failed");
+      return 1;
+    }
+#endif
+
+  if (pthread_mutexattr_destroy (&a) != 0)
+    {
+      puts ("mutexattr_destroy failed");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-robust2.c b/nptl/tst-robust2.c
new file mode 100644
index 0000000000..cf603feb4d
--- /dev/null
+++ b/nptl/tst-robust2.c
@@ -0,0 +1,3 @@
+#define AFTER_JOIN 1
+#define LOCK(m) pthread_mutex_trylock (m)
+#include "tst-robust1.c"
diff --git a/nptl/tst-robust3.c b/nptl/tst-robust3.c
new file mode 100644
index 0000000000..e56f2762c7
--- /dev/null
+++ b/nptl/tst-robust3.c
@@ -0,0 +1,20 @@
+#include <time.h>
+#include <sys/time.h>
+
+
+static struct timespec tmo;
+
+
+#define PREPARE_TMO \
+  do {									      \
+    struct timeval tv;							      \
+    gettimeofday (&tv, NULL);						      \
+									      \
+    /* Define the timeout as one hour in the future.  */		      \
+    tmo.tv_sec = tv.tv_sec + 3600;					      \
+    tmo.tv_nsec = 0;							      \
+  } while (0)
+
+
+#define LOCK(m) pthread_mutex_timedlock (m, &tmo)
+#include "tst-robust1.c"
diff --git a/nptl/tst-robust4.c b/nptl/tst-robust4.c
new file mode 100644
index 0000000000..b9c42b85b9
--- /dev/null
+++ b/nptl/tst-robust4.c
@@ -0,0 +1,2 @@
+#define NOT_CONSISTENT 1
+#include "tst-robust1.c"
diff --git a/nptl/tst-robust5.c b/nptl/tst-robust5.c
new file mode 100644
index 0000000000..b83d3d66cb
--- /dev/null
+++ b/nptl/tst-robust5.c
@@ -0,0 +1,2 @@
+#define NOT_CONSISTENT 1
+#include "tst-robust2.c"
diff --git a/nptl/tst-robust6.c b/nptl/tst-robust6.c
new file mode 100644
index 0000000000..6713396de1
--- /dev/null
+++ b/nptl/tst-robust6.c
@@ -0,0 +1,2 @@
+#define NOT_CONSISTENT 1
+#include "tst-robust3.c"
diff --git a/nptl/tst-typesizes.c b/nptl/tst-typesizes.c
new file mode 100644
index 0000000000..db8936f5f4
--- /dev/null
+++ b/nptl/tst-typesizes.c
@@ -0,0 +1,68 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+   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 <stdio.h>
+#include <pthreadP.h>
+#include <semaphore.h>
+
+
+static int
+do_test (void)
+{
+  int result = 0;
+
+#define TEST_TYPE(name) \
+  printf ("%s: ", #name);						      \
+  if (sizeof (name) != sizeof (((name *) 0)->__size))			      \
+    {									      \
+      printf ("expected %zu, is %zu\n",					      \
+	      sizeof (((name *) 0)->__size), sizeof (name));		      \
+      result = 1;							      \
+    }									      \
+  else									      \
+    puts ("OK")
+
+  TEST_TYPE (pthread_mutex_t);
+  TEST_TYPE (pthread_cond_t);
+  TEST_TYPE (pthread_rwlock_t);
+
+#define TEST_TYPE2(name, internal)					      \
+  printf ("%s: ", #name);						      \
+  if (sizeof (((name *) 0)->__size) < sizeof (internal))		      \
+    {									      \
+      printf ("expected %zu, is %zu\n",					      \
+	      sizeof (((name *) 0)->__size), sizeof (internal));	      \
+      result = 1;							      \
+    }									      \
+  else									      \
+    puts ("OK")
+
+  TEST_TYPE2 (pthread_attr_t, struct pthread_attr);
+  TEST_TYPE2 (pthread_mutexattr_t, struct pthread_mutexattr);
+  TEST_TYPE2 (pthread_condattr_t, struct pthread_condattr);
+  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);
+
+  return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"