about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>2006-07-29 23:12:43 +0000
committerRoland McGrath <roland@gnu.org>2006-07-29 23:12:43 +0000
commitab5823b4b6e760345d347b98830ccc75aa81bff6 (patch)
treef9b25d5f9a16e7ce0318aaf3adcccec0e83fd804
parentaa583d2ff9fca922771d88f1afa255847f2aa4ed (diff)
downloadglibc-ab5823b4b6e760345d347b98830ccc75aa81bff6.tar.gz
glibc-ab5823b4b6e760345d347b98830ccc75aa81bff6.tar.xz
glibc-ab5823b4b6e760345d347b98830ccc75aa81bff6.zip
Updated to fedora-glibc-20060729T2255 cvs/fedora-glibc-2_4_90-14
-rw-r--r--ChangeLog42
-rw-r--r--NEWS5
-rw-r--r--dlfcn/Makefile13
-rw-r--r--dlfcn/bug-atexit3-lib.cc23
-rw-r--r--dlfcn/bug-atexit3.c18
-rw-r--r--dlfcn/dlmopen.c17
-rw-r--r--fedora/branch.mk4
-rw-r--r--fedora/glibc.spec.in6
-rw-r--r--include/time.h2
-rw-r--r--include/unistd.h2
-rw-r--r--nptl/ChangeLog66
-rw-r--r--nptl/Makefile5
-rw-r--r--nptl/descr.h40
-rw-r--r--nptl/pthreadP.h21
-rw-r--r--nptl/pthread_create.c8
-rw-r--r--nptl/pthread_mutex_destroy.c1
-rw-r--r--nptl/pthread_mutex_init.c28
-rw-r--r--nptl/pthread_mutex_lock.c129
-rw-r--r--nptl/pthread_mutex_setprioceiling.c2
-rw-r--r--nptl/pthread_mutex_timedlock.c150
-rw-r--r--nptl/pthread_mutex_trylock.c124
-rw-r--r--nptl/pthread_mutex_unlock.c83
-rw-r--r--nptl/sysdeps/pthread/pthread_cond_broadcast.c8
-rw-r--r--nptl/sysdeps/unix/sysv/linux/Makefile2
-rw-r--r--nptl/sysdeps/unix/sysv/linux/alpha/lowlevellock.h3
-rw-r--r--nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h8
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S7
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h3
-rw-r--r--nptl/sysdeps/unix/sysv/linux/ia64/lowlevellock.h3
-rw-r--r--nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h3
-rw-r--r--nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym6
-rw-r--r--nptl/sysdeps/unix/sysv/linux/s390/lowlevellock.h3
-rw-r--r--nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.h3
-rw-r--r--nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.h3
-rw-r--r--nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h3
-rw-r--r--nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S7
-rw-r--r--nptl/tst-mutex1.c22
-rw-r--r--nptl/tst-mutex2.c67
-rw-r--r--nptl/tst-mutex3.c23
-rw-r--r--nptl/tst-mutex4.c99
-rw-r--r--nptl/tst-mutex5.c20
-rw-r--r--nptl/tst-mutex6.c22
-rw-r--r--nptl/tst-mutex7.c52
-rw-r--r--nptl/tst-mutex7a.c2
-rw-r--r--nptl/tst-mutex9.c22
-rw-r--r--nptl/tst-mutexpi1.c27
-rw-r--r--nptl/tst-mutexpi2.c2
-rw-r--r--nptl/tst-mutexpi3.c2
-rw-r--r--nptl/tst-mutexpi4.c2
-rw-r--r--nptl/tst-mutexpi5.c2
-rw-r--r--nptl/tst-mutexpi5a.c2
-rw-r--r--nptl/tst-mutexpi6.c27
-rw-r--r--nptl/tst-mutexpi7.c2
-rw-r--r--nptl/tst-mutexpi7a.c2
-rw-r--r--nptl/tst-mutexpi8.c2
-rw-r--r--nptl/tst-mutexpi9.c2
-rw-r--r--nptl/tst-robust1.c28
-rw-r--r--nptl/tst-robust7.c25
-rw-r--r--nptl/tst-robust8.c13
-rw-r--r--nptl/tst-robustpi1.c2
-rw-r--r--nptl/tst-robustpi2.c2
-rw-r--r--nptl/tst-robustpi3.c2
-rw-r--r--nptl/tst-robustpi4.c2
-rw-r--r--nptl/tst-robustpi5.c2
-rw-r--r--nptl/tst-robustpi6.c2
-rw-r--r--nptl/tst-robustpi7.c2
-rw-r--r--nptl/tst-robustpi8.c2
-rw-r--r--stdlib/cxa_atexit.c8
-rw-r--r--stdlib/cxa_finalize.c34
-rw-r--r--stdlib/exit.h5
-rw-r--r--sysdeps/unix/sysv/linux/alpha/bits/fcntl.h2
-rw-r--r--sysdeps/unix/sysv/linux/i386/bits/fcntl.h2
-rw-r--r--sysdeps/unix/sysv/linux/ia64/bits/fcntl.h2
-rw-r--r--sysdeps/unix/sysv/linux/kernel-features.h17
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h2
-rw-r--r--sysdeps/unix/sysv/linux/s390/bits/fcntl.h2
-rw-r--r--sysdeps/unix/sysv/linux/sh/bits/fcntl.h2
-rw-r--r--sysdeps/unix/sysv/linux/sparc/bits/fcntl.h2
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/bits/fcntl.h2
79 files changed, 1284 insertions, 130 deletions
diff --git a/ChangeLog b/ChangeLog
index 7a97b2fabe..dfca3fceb3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,45 @@
+2006-07-28  Ulrich Drepper  <drepper@redhat.com>
+
+	* sysdeps/unix/sysv/linux/kernel-features.h: Define
+	__ASSUME_FUTEX_LOCK_PI.
+	* include/time.h: Declare __nanosleep_nocancel.
+	* include/unistd.h: Declare __pause_nocancel.
+
+	* dlfcn/Makefile (LDLIBS-bug-atexit3-lib.so): Use this instead of
+	LDFLAGS.  Add -lgcc_eh and libc_nonshared (again) to make sure we
+	get the __stack_chk_fail_local definition when it's needed.
+
+2006-07-26  Ulrich Drepper  <drepper@redhat.com>
+
+	* dlfcn/Makefile: Add rules to build and run bug-atexit3.
+	* dlfcn/bug-atexit3.c: New file.
+	* dlfcn/bug-atexit3-lib.cc: New file.
+
+	* dlfcn/dlmopen.c (dlmopen_doit): Don't allow RTLD_GLOBAL to be
+	used when the namespace is not the base namespace.
+
+2006-07-26  Gavin Romig-Koch  <gavin@redhat.com>
+
+	* stdlib/cxa_atexit.c (__new_exitfn_called): New variable.
+	(__new_exitfn): Bump it in every successful call.
+	* stdlib/cxa_finalize.c (__cxa_finalize): If destructor registered
+	more exit handlers, call them right away.
+	* stdlib/exit.h: Declare __new_exitfn_called.
+
+2006-07-25  Ulrich Drepper  <drepper@redhat.com>
+
+	* stdlib/cxa_finalize.c (__cxa_finalize): Fix race condition when
+	calling registered handler.
+
+	* sysdeps/unix/sysv/linux/sparc/bits/fcntl.h: Fix comment.
+	* sysdeps/unix/sysv/linux/ia64/bits/fcntl.h: Likewise.
+	* sysdeps/unix/sysv/linux/sh/bits/fcntl.h: Likewise.
+	* sysdeps/unix/sysv/linux/i386/bits/fcntl.h: Likewise.
+	* sysdeps/unix/sysv/linux/s390/bits/fcntl.h: Likewise.
+	* sysdeps/unix/sysv/linux/x86_64/bits/fcntl.h: Likewise.
+	* sysdeps/unix/sysv/linux/alpha/bits/fcntl.h: Likewise.
+	* sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h: Likewise.
+
 2006-07-10  Ulrich Drepper  <drepper@redhat.com>
 
 	* elf/dl-lookup.c (dl_new_hash): New functions.
diff --git a/NEWS b/NEWS
index 0f73029978..55855ad81a 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-GNU C Library NEWS -- history of user-visible changes.  2006-07-10
+GNU C Library NEWS -- history of user-visible changes.  2006-07-28
 Copyright (C) 1992-2002,2003,2004,2005,2006 Free Software Foundation, Inc.
 See the end for copying conditions.
 
@@ -33,6 +33,9 @@ Version 2.5
 
 * Support for the new ELF hash table format was added by Ulrich Drepper.
 
+* Support for priority inheritance mutexes added by Jakub Jelinek and
+  Ulrich Drepper.
+
 
 Version 2.4
 
diff --git a/dlfcn/Makefile b/dlfcn/Makefile
index bfa181528b..649f61de63 100644
--- a/dlfcn/Makefile
+++ b/dlfcn/Makefile
@@ -1,4 +1,4 @@
-# Copyright (C) 1995-2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+# Copyright (C) 1995-2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 # This file is part of the GNU C Library.
 
 # The GNU C Library is free software; you can redistribute it and/or
@@ -40,7 +40,8 @@ endif
 
 ifeq (yes,$(build-shared))
 tests = glrefmain failtest tst-dladdr default errmsg1 tstcxaatexit \
-	bug-dlopen1 bug-dlsym1 tst-dlinfo bug-atexit1 bug-atexit2
+	bug-dlopen1 bug-dlsym1 tst-dlinfo bug-atexit1 bug-atexit2 \
+	bug-atexit3
 ifeq (yes,$(have-protected))
 tests += tstatexit
 endif
@@ -48,7 +49,7 @@ endif
 modules-names = glreflib1 glreflib2 failtestmod defaultmod1 defaultmod2 \
 		errmsg1mod modatexit modcxaatexit \
 		bug-dlsym1-lib1 bug-dlsym1-lib2 bug-atexit1-lib \
-		bug-atexit2-lib
+		bug-atexit2-lib bug-atexit3-lib
 
 failtestmod.so-no-z-defs = yes
 glreflib2.so-no-z-defs = yes
@@ -135,6 +136,12 @@ $(objpfx)bug-atexit2.out: $(objpfx)bug-atexit2-lib.so
 $(objpfx)bug-atexit2-lib.so: $(common-objpfx)libc.so \
 			     $(common-objpfx)libc_nonshared.a
 
+LDLIBS-bug-atexit3-lib.so = -lstdc++ -lgcc_eh $(common-objpfx)libc_nonshared.a
+$(objpfx)bug-atexit3: $(libdl)
+$(objpfx)bug-atexit3.out: $(objpfx)bug-atexit3-lib.so
+$(objpfx)bug-atexit3-lib.so: $(common-objpfx)libc.so \
+			     $(common-objpfx)libc_nonshared.a
+
 
 # Depend on libc.so so a DT_NEEDED is generated in the shared objects.
 # This ensures they will load libc.so for needed symbols if loaded by
diff --git a/dlfcn/bug-atexit3-lib.cc b/dlfcn/bug-atexit3-lib.cc
new file mode 100644
index 0000000000..3d01ea81d2
--- /dev/null
+++ b/dlfcn/bug-atexit3-lib.cc
@@ -0,0 +1,23 @@
+#include <unistd.h>
+
+struct statclass
+{
+  statclass()
+  {
+    write (1, "statclass\n", 10);
+  }
+  ~statclass()
+  {
+    write (1, "~statclass\n", 11);
+  }
+};
+
+struct extclass
+{
+  ~extclass()
+  {
+    static statclass var;
+  }
+};
+
+extclass globvar;
diff --git a/dlfcn/bug-atexit3.c b/dlfcn/bug-atexit3.c
new file mode 100644
index 0000000000..897eca8a86
--- /dev/null
+++ b/dlfcn/bug-atexit3.c
@@ -0,0 +1,18 @@
+#include <dlfcn.h>
+#include <stdio.h>
+
+static int
+do_test (void)
+{
+  void *handle = dlopen ("$ORIGIN/bug-atexit3-lib.so", RTLD_LAZY);
+  if (handle == NULL)
+    {
+      printf ("dlopen failed: %s\n", dlerror ());
+      return 1;
+    }
+  dlclose (handle);
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/dlfcn/dlmopen.c b/dlfcn/dlmopen.c
index 0a6d47ea2e..0c6915493b 100644
--- a/dlfcn/dlmopen.c
+++ b/dlfcn/dlmopen.c
@@ -1,5 +1,5 @@
 /* Load a shared object at run time.
-   Copyright (C) 1995,96,97,98,99,2000,2003,2004 Free Software Foundation, Inc.
+   Copyright (C) 1995-2000,2003,2004,2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -55,12 +55,19 @@ dlmopen_doit (void *a)
 
   /* Non-shared code has no support for multiple namespaces.  */
   if (args->nsid != LM_ID_BASE)
+    {
 # ifdef SHARED
-    /* If trying to open the link map for the main executable the namespace
-       must be the main one.  */
-    if (args->file == NULL)
+      /* If trying to open the link map for the main executable the namespace
+	 must be the main one.  */
+      if (args->file == NULL)
 # endif
-      GLRO(dl_signal_error) (EINVAL, NULL, NULL, N_("invalid namespace"));
+	GLRO(dl_signal_error) (EINVAL, NULL, NULL, N_("invalid namespace"));
+
+      /* It makes no sense to use RTLD_GLOBAL when loading a DSO into
+	 a namespace other than the base namespace.  */
+      if (__builtin_expect (args->mode & RTLD_GLOBAL, 0))
+	GLRO(dl_signal_error) (EINVAL, NULL, NULL, N_("invalid mode"));
+    }
 
   args->new = GLRO(dl_open) (args->file ?: "", args->mode | __RTLD_DLOPEN,
 			     args->caller,
diff --git a/fedora/branch.mk b/fedora/branch.mk
index 124031f0ac..cd60348072 100644
--- a/fedora/branch.mk
+++ b/fedora/branch.mk
@@ -3,5 +3,5 @@ glibc-branch := fedora
 glibc-base := HEAD
 DIST_BRANCH := devel
 COLLECTION := dist-fc4
-fedora-sync-date := 2006-07-10 22:06 UTC
-fedora-sync-tag := fedora-glibc-20060710T2206
+fedora-sync-date := 2006-07-29 22:55 UTC
+fedora-sync-tag := fedora-glibc-20060729T2255
diff --git a/fedora/glibc.spec.in b/fedora/glibc.spec.in
index 59df1b9005..7bb140e570 100644
--- a/fedora/glibc.spec.in
+++ b/fedora/glibc.spec.in
@@ -1,4 +1,4 @@
-%define glibcrelease 13
+%define glibcrelease 14
 %define auxarches i586 i686 athlon sparcv9 alphaev6
 %define xenarches i686 athlon
 %ifarch %{xenarches}
@@ -1433,6 +1433,10 @@ rm -f *.filelist*
 %endif
 
 %changelog
+* Sat Jul 29 2006 Roland McGrath <roland@redhat.com> - 2.4.90-14
+- fix missing destructor calls in dlclose (#197932)
+- PI mutex support
+
 * Tue Jul 10 2006 Jakub Jelinek <jakub@redhat.com> 2.4.90-13
 - DT_GNU_HASH support
 
diff --git a/include/time.h b/include/time.h
index 224736540b..f2a6489efd 100644
--- a/include/time.h
+++ b/include/time.h
@@ -81,6 +81,8 @@ extern long int __tzname_max (void);
 
 extern int __nanosleep (__const struct timespec *__requested_time,
 			struct timespec *__remaining);
+extern int __nanosleep_nocancel (__const struct timespec *__requested_time,
+				 struct timespec *__remaining);
 libc_hidden_proto(__nanosleep)
 extern int __getdate_r (__const char *__string, struct tm *__resbufp);
 
diff --git a/include/unistd.h b/include/unistd.h
index f8f15ed019..fb7a044b57 100644
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -162,5 +162,7 @@ extern __pid_t __libc_fork (void);
 /* Suspend the process until a signal arrives.
    This always returns -1 and sets `errno' to EINTR.  */
 extern int __libc_pause (void);
+/* Not cancelable variant.  */
+extern int __pause_nocancel (void);
 
 #endif
diff --git a/nptl/ChangeLog b/nptl/ChangeLog
index 02b4c2f191..b9705ee065 100644
--- a/nptl/ChangeLog
+++ b/nptl/ChangeLog
@@ -1,3 +1,69 @@
+2006-07-28  Ulrich Drepper  <drepper@redhat.com>
+	    Jakub Jelinek  <jakub@redhat.com>
+
+	* descr.h: Change ENQUEUE_MUTEX and DEQUEUE_MUTEX for bit 0
+	notification of PI mutex.  Add ENQUEUE_MUTEX_PI.
+	* pthreadP.h: Define PTHREAD_MUTEX_PI_* macros for PI mutex types.
+	* pthread_mutex_setprioceilining.c: Adjust for mutex type name change.
+	* pthread_mutex_init.c: Add support for priority inheritance mutex.
+	* pthread_mutex_lock.c: Likewise.
+	* pthread_mutex_timedlock.c: Likewise.
+	* pthread_mutex_trylock.c: Likewise.
+	* pthread_mutex_unlock.c: Likewise.
+	* sysdeps/pthread/pthread_cond_broadcast.c: For PI mutexes wake
+	all mutexes.
+	* sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.c: Likewise.
+	* sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.c: Likewise.
+	* sysdeps/unix/sysv/linux/pthread-pi-defines.sym: New file.
+	* sysdeps/unix/sysv/linux/Makefile (gen-as-const-header): Add
+	pthread-pi-defines.sym.
+	* sysdeps/unix/sysv/linux/i386/lowlevellock.h: Define FUTEX_LOCK_PI,
+	FUTEX_UNLOCK_PI, and FUTEX_TRYLOCK_PI.
+	* sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Likewise.
+	* sysdeps/unix/sysv/linux/alpha/lowlevellock.h: Likewise.
+	* sysdeps/unix/sysv/linux/ia64/lowlevellock.h: Likewise.
+	* sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: Likewise.
+	* sysdeps/unix/sysv/linux/s390/lowlevellock.h: Likewise.
+	* sysdeps/unix/sysv/linux/sh/lowlevellock.h: Likewise.
+	* sysdeps/unix/sysv/linux/sparc/lowlevellock.h: Likewise.
+	* sysdeps/unix/sysv/linux/bits/posix_opt.h: Define
+	_POSIX_THREAD_PRIO_INHERIT to 200112L.
+	* tst-mutex1.c: Adjust to allow use in PI mutex test.
+	* tst-mutex2.c: Likewise.
+	* tst-mutex3.c: Likewise.
+	* tst-mutex4.c: Likewise.
+	* tst-mutex5.c: Likewise.
+	* tst-mutex6.c: Likewise.
+	* tst-mutex7.c: Likewise.
+	* tst-mutex7a.c: Likewise.
+	* tst-mutex8.c: Likewise.
+	* tst-mutex9.c: Likewise.
+	* tst-robust1.c: Likewise.
+	* tst-robust7.c: Likewise.
+	* tst-robust8.c: Likewise.
+	* tst-mutexpi1.c: New file.
+	* tst-mutexpi2.c: New file.
+	* tst-mutexpi3.c: New file.
+	* tst-mutexpi4.c: New file.
+	* tst-mutexpi5.c: New file.
+	* tst-mutexpi6.c: New file.
+	* tst-mutexpi7.c: New file.
+	* tst-mutexpi7a.c: New file.
+	* tst-mutexpi8.c: New file.
+	* tst-mutexpi9.c: New file.
+	* 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.
+	* tst-robust8.c: New file.
+	* Makefile (tests): Add the new tests.
+
+	* pthread_create.c (start_thread): Add some casts to avoid warnings.
+	* pthread_mutex_destroy.c: Remove unneeded label.
+
 2006-07-01  Ulrich Drepper  <drepper@redhat.com>
 
 	* pthread_mutex_init.c (__pthread_mutex_init): Move some
diff --git a/nptl/Makefile b/nptl/Makefile
index e430b8d6cb..6a80bc1183 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -200,6 +200,9 @@ 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-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 tst-mutexpi5 \
+	tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a tst-mutexpi8 \
+	tst-mutexpi9 \
 	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 tst-cond12 tst-cond13 \
@@ -207,6 +210,8 @@ tests = tst-typesizes \
 	tst-cond20 tst-cond21 \
 	tst-robust1 tst-robust2 tst-robust3 tst-robust4 tst-robust5 \
 	tst-robust6 tst-robust7 tst-robust8 \
+	tst-robustpi1 tst-robustpi2 tst-robustpi3 tst-robustpi4 \
+	tst-robustpi5 tst-robustpi6 tst-robustpi7 tst-robustpi8 \
 	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/descr.h b/nptl/descr.h
index f89d3240da..607aa9fcdb 100644
--- a/nptl/descr.h
+++ b/nptl/descr.h
@@ -155,23 +155,28 @@ struct pthread
      first.  */
 # define QUEUE_PTR_ADJUST (offsetof (__pthread_list_t, __next))
 
-# define ENQUEUE_MUTEX(mutex) \
+# define ENQUEUE_MUTEX_BOTH(mutex, val)					      \
   do {									      \
-    __pthread_list_t *next = (THREAD_GETMEM (THREAD_SELF, robust_head.list)   \
-			      - QUEUE_PTR_ADJUST);			      \
+    __pthread_list_t *next = (__pthread_list_t *)			      \
+      ((((uintptr_t) THREAD_GETMEM (THREAD_SELF, robust_head.list)) & ~1ul)   \
+       - QUEUE_PTR_ADJUST);						      \
     next->__prev = (void *) &mutex->__data.__list.__next;		      \
-    mutex->__data.__list.__next = (void *) &next->__next;		      \
+    mutex->__data.__list.__next = THREAD_GETMEM (THREAD_SELF,		      \
+						 robust_head.list);	      \
     mutex->__data.__list.__prev = (void *) &THREAD_SELF->robust_head;	      \
     THREAD_SETMEM (THREAD_SELF, robust_head.list,			      \
-		   &mutex->__data.__list.__next);			      \
+		   (void *) (((uintptr_t) &mutex->__data.__list.__next)	      \
+			     | val));					      \
   } while (0)
 # define DEQUEUE_MUTEX(mutex) \
   do {									      \
     __pthread_list_t *next = (__pthread_list_t *)			      \
-      ((char *) mutex->__data.__list.__next - QUEUE_PTR_ADJUST);	      \
+      ((char *) (((uintptr_t) mutex->__data.__list.__next) & ~1ul)	      \
+       - QUEUE_PTR_ADJUST);						      \
     next->__prev = mutex->__data.__list.__prev;				      \
     __pthread_list_t *prev = (__pthread_list_t *)			      \
-      ((char *) mutex->__data.__list.__prev - QUEUE_PTR_ADJUST);	      \
+      ((char *) (((uintptr_t) mutex->__data.__list.__prev) & ~1ul)	      \
+       - QUEUE_PTR_ADJUST);						      \
     prev->__next = mutex->__data.__list.__next;				      \
     mutex->__data.__list.__prev = NULL;					      \
     mutex->__data.__list.__next = NULL;					      \
@@ -183,27 +188,36 @@ struct pthread
     struct robust_list_head robust_head;
   };
 
-# define ENQUEUE_MUTEX(mutex) \
+# define ENQUEUE_MUTEX_BOTH(mutex, val)					      \
   do {									      \
     mutex->__data.__list.__next						      \
       = THREAD_GETMEM (THREAD_SELF, robust_list.__next);		      \
-    THREAD_SETMEM (THREAD_SELF, robust_list.__next, &mutex->__data.__list);   \
+    THREAD_SETMEM (THREAD_SELF, robust_list.__next,			      \
+		   ((uintptr_t) &mutex->__data.__list) | val);		      \
   } while (0)
 # define DEQUEUE_MUTEX(mutex) \
   do {									      \
-    __pthread_slist_t *runp = THREAD_GETMEM (THREAD_SELF, robust_list.__next);\
+    __pthread_slist_t *runp = (__pthread_slist_t *)			      \
+      (((uintptr_t) THREAD_GETMEM (THREAD_SELF, robust_list.__next)) & ~1ul); \
     if (runp == &mutex->__data.__list)					      \
       THREAD_SETMEM (THREAD_SELF, robust_list.__next, runp->__next);	      \
     else								      \
       {									      \
-	while (runp->__next != &mutex->__data.__list)			      \
-	  runp = runp->__next;						      \
+	__pthread_slist_t *next = (__pthread_slist_t *)		      \
+	  (((uintptr_t) runp->__next) & ~1ul);				      \
+	while (next != &mutex->__data.__list)				      \
+	  {								      \
+	    runp = next;						      \
+	    next = (__pthread_slist_t *) (((uintptr_t) runp->__next) & ~1ul); \
+	  }								      \
 									      \
-	runp->__next = runp->__next->__next;				      \
+	runp->__next = next->__next;					      \
 	mutex->__data.__list.__next = NULL;				      \
       }									      \
   } while (0)
 #endif
+#define ENQUEUE_MUTEX(mutex) ENQUEUE_MUTEX_BOTH (mutex, 0)
+#define ENQUEUE_MUTEX_PI(mutex) ENQUEUE_MUTEX_BOTH (mutex, 1)
 
   /* List of cleanup buffers.  */
   struct _pthread_cleanup_buffer *cleanup;
diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
index c7f57e235a..dc98bb19c0 100644
--- a/nptl/pthreadP.h
+++ b/nptl/pthreadP.h
@@ -61,6 +61,7 @@
 /* Internal mutex type value.  */
 enum
 {
+  PTHREAD_MUTEX_KIND_MASK_NP = 3,
   PTHREAD_MUTEX_ROBUST_NORMAL_NP = 16,
   PTHREAD_MUTEX_ROBUST_RECURSIVE_NP
   = PTHREAD_MUTEX_ROBUST_NORMAL_NP | PTHREAD_MUTEX_RECURSIVE_NP,
@@ -68,8 +69,24 @@ enum
   = PTHREAD_MUTEX_ROBUST_NORMAL_NP | PTHREAD_MUTEX_ERRORCHECK_NP,
   PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP
   = PTHREAD_MUTEX_ROBUST_NORMAL_NP | PTHREAD_MUTEX_ADAPTIVE_NP,
-  PTHREAD_MUTEX_PRIO_INHERIT_PRIVATE_NP = 32,
-  PTHREAD_MUTEX_PRIO_PROTECT_PRIVATE_NP = 64
+  PTHREAD_MUTEX_PRIO_INHERIT_NP = 32,
+  PTHREAD_MUTEX_PI_NORMAL_NP
+  = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_NORMAL,
+  PTHREAD_MUTEX_PI_RECURSIVE_NP
+  = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_RECURSIVE_NP,
+  PTHREAD_MUTEX_PI_ERRORCHECK_NP
+  = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ERRORCHECK_NP,
+  PTHREAD_MUTEX_PI_ADAPTIVE_NP
+  = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ADAPTIVE_NP,
+  PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP
+  = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_NORMAL_NP,
+  PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP
+  = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_RECURSIVE_NP,
+  PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP
+  = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP,
+  PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP
+  = PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP,
+  PTHREAD_MUTEX_PRIO_PROTECT_NP = 64
 };
 #define PTHREAD_MUTEX_PRIO_CEILING_SHIFT	16
 #define PTHREAD_MUTEX_PRIO_CEILING_MASK		0x00ff0000
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
index 71365a17e8..c1ac199bb9 100644
--- a/nptl/pthread_create.c
+++ b/nptl/pthread_create.c
@@ -330,9 +330,11 @@ start_thread (void *arg)
 # else
   __pthread_slist_t *robust = pd->robust_list.__next;
 # endif
-/* We let the kernel do the notification if it is able to do so.  */
+  /* We let the kernel do the notification if it is able to do so.
+     If we have to do it here there for sure are no PI mutexes involved
+     since the kernel support for them is even more recent.  */
   if (__set_robust_list_avail < 0
-      && __builtin_expect (robust != &pd->robust_head, 0))
+      && __builtin_expect (robust != (void *) &pd->robust_head, 0))
     {
       do
 	{
@@ -348,7 +350,7 @@ start_thread (void *arg)
 
 	  lll_robust_mutex_dead (this->__lock);
 	}
-      while (robust != &pd->robust_head);
+      while (robust != (void *) &pd->robust_head);
     }
 #endif
 
diff --git a/nptl/pthread_mutex_destroy.c b/nptl/pthread_mutex_destroy.c
index 7829979f35..e2c9f8a39f 100644
--- a/nptl/pthread_mutex_destroy.c
+++ b/nptl/pthread_mutex_destroy.c
@@ -30,7 +30,6 @@ __pthread_mutex_destroy (mutex)
     return EBUSY;
 
   /* Set to an invalid value.  */
- dead_robust_mutex:
   mutex->__data.__kind = -1;
 
   return 0;
diff --git a/nptl/pthread_mutex_init.c b/nptl/pthread_mutex_init.c
index c3f9c2d1c0..6ceca86052 100644
--- a/nptl/pthread_mutex_init.c
+++ b/nptl/pthread_mutex_init.c
@@ -29,6 +29,11 @@ static const struct pthread_mutexattr default_attr =
   };
 
 
+#ifndef __ASSUME_FUTEX_LOCK_PI
+static int tpi_supported;
+#endif
+
+
 int
 __pthread_mutex_init (mutex, mutexattr)
      pthread_mutex_t *mutex;
@@ -41,8 +46,7 @@ __pthread_mutex_init (mutex, mutexattr)
   imutexattr = (const struct pthread_mutexattr *) mutexattr ?: &default_attr;
 
   /* Sanity checks.  */
-  // XXX For now we don't support priority inherited or priority protected
-  // XXX mutexes.
+  // XXX For now we don't support priority protected mutexes.
   switch (__builtin_expect (imutexattr->mutexkind
 			    & PTHREAD_MUTEXATTR_PROTOCOL_MASK,
 			    PTHREAD_PRIO_NONE
@@ -51,6 +55,22 @@ __pthread_mutex_init (mutex, mutexattr)
     case PTHREAD_PRIO_NONE << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT:
       break;
 
+    case PTHREAD_PRIO_INHERIT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT:
+#ifndef __ASSUME_FUTEX_LOCK_PI
+      if (__builtin_expect (tpi_supported == 0, 0))
+	{
+	  int lock = 0;
+	  INTERNAL_SYSCALL_DECL (err);
+	  int ret = INTERNAL_SYSCALL (futex, err, 4, &lock, FUTEX_UNLOCK_PI,
+				      0, 0);
+	  assert (INTERNAL_SYSCALL_ERROR_P (ret, err));
+	  tpi_supported = INTERNAL_SYSCALL_ERRNO (ret, err) == ENOSYS ? -1 : 1;
+	}
+      if (__builtin_expect (tpi_supported < 0, 0))
+	return ENOTSUP;
+#endif
+      break;
+
     default:
       return ENOTSUP;
     }
@@ -75,11 +95,11 @@ __pthread_mutex_init (mutex, mutexattr)
   switch (imutexattr->mutexkind & PTHREAD_MUTEXATTR_PROTOCOL_MASK)
     {
     case PTHREAD_PRIO_INHERIT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT:
-      mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_INHERIT_PRIVATE_NP;
+      mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_INHERIT_NP;
       break;
 
     case PTHREAD_PRIO_PROTECT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT:
-      mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_PROTECT_PRIVATE_NP;
+      mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_PROTECT_NP;
       if (PTHREAD_MUTEX_PRIO_CEILING_MASK
 	  == PTHREAD_MUTEXATTR_PRIO_CEILING_MASK)
 	mutex->__data.__kind |= (imutexattr->mutexkind
diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c
index 06eef49c71..5345766883 100644
--- a/nptl/pthread_mutex_lock.c
+++ b/nptl/pthread_mutex_lock.c
@@ -20,6 +20,7 @@
 #include <assert.h>
 #include <errno.h>
 #include <stdlib.h>
+#include <unistd.h>
 #include "pthreadP.h"
 #include <lowlevellock.h>
 
@@ -205,6 +206,134 @@ __pthread_mutex_lock (mutex)
       THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
       break;
 
+    case PTHREAD_MUTEX_PI_RECURSIVE_NP:
+    case PTHREAD_MUTEX_PI_ERRORCHECK_NP:
+    case PTHREAD_MUTEX_PI_NORMAL_NP:
+    case PTHREAD_MUTEX_PI_ADAPTIVE_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP:
+      {
+	int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
+	int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
+
+	if (robust)
+	  /* Note: robust PI futexes are signaled by setting bit 0.  */
+	  THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
+			 (void *) (((uintptr_t) &mutex->__data.__list.__next)
+				   | 1));
+
+	oldval = mutex->__data.__lock;
+
+	/* Check whether we already hold the mutex.  */
+	if (__builtin_expect ((oldval & FUTEX_TID_MASK) == id, 0))
+	  {
+	    if (kind == PTHREAD_MUTEX_ERRORCHECK_NP)
+	      {
+		THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+		return EDEADLK;
+	      }
+
+	    if (kind == PTHREAD_MUTEX_RECURSIVE_NP)
+	      {
+		THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+		/* Just bump the counter.  */
+		if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
+		  /* Overflow of the counter.  */
+		  return EAGAIN;
+
+		++mutex->__data.__count;
+
+		return 0;
+	      }
+	  }
+
+	int newval = id;
+#ifdef NO_INCR
+	newval |= FUTEX_WAITERS;
+#endif
+	oldval = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+						      newval, 0);
+
+	if (oldval != 0)
+	  {
+	    /* The mutex is locked.  The kernel will now take care of
+	       everything.  */
+	    INTERNAL_SYSCALL_DECL (__err);
+	    int e = INTERNAL_SYSCALL (futex, __err, 4, &mutex->__data.__lock,
+				      FUTEX_LOCK_PI, 1, 0);
+
+	    if (INTERNAL_SYSCALL_ERROR_P (e, __err)
+		&& (INTERNAL_SYSCALL_ERRNO (e, __err) == ESRCH
+		    || INTERNAL_SYSCALL_ERRNO (e, __err) == EDEADLK))
+	      {
+		assert (INTERNAL_SYSCALL_ERRNO (e, __err) != EDEADLK
+			|| (kind != PTHREAD_MUTEX_ERRORCHECK_NP
+			    && kind != PTHREAD_MUTEX_RECURSIVE_NP));
+		/* ESRCH can happen only for non-robust PI mutexes where
+		   the owner of the lock died.  */
+		assert (INTERNAL_SYSCALL_ERRNO (e, __err) != ESRCH || !robust);
+
+		/* Delay the thread indefinitely.  */
+		while (1)
+		  __pause_nocancel ();
+	      }
+
+	    oldval = mutex->__data.__lock;
+
+	    assert (robust || (oldval & FUTEX_OWNER_DIED) == 0);
+	  }
+
+	if (__builtin_expect (oldval & FUTEX_OWNER_DIED, 0))
+	  {
+	    atomic_and (&mutex->__data.__lock, ~FUTEX_OWNER_DIED);
+
+	    /* We got the mutex.  */
+	    mutex->__data.__count = 1;
+	    /* But it is inconsistent unless marked otherwise.  */
+	    mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
+
+	    ENQUEUE_MUTEX_PI (mutex);
+	    THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+	    /* Note that we deliberately exit here.  If we fall
+	       through to the end of the function __nusers would be
+	       incremented which is not correct because the old owner
+	       has to be discounted.  If we are not supposed to
+	       increment __nusers we actually have to decrement it here.  */
+#ifdef NO_INCR
+	    --mutex->__data.__nusers;
+#endif
+
+	    return EOWNERDEAD;
+	  }
+
+	if (robust
+	    && __builtin_expect (mutex->__data.__owner
+				 == PTHREAD_MUTEX_NOTRECOVERABLE, 0))
+	  {
+	    /* This mutex is now not recoverable.  */
+	    mutex->__data.__count = 0;
+
+	    INTERNAL_SYSCALL_DECL (__err);
+	    INTERNAL_SYSCALL (futex, __err, 4, &mutex->__data.__lock,
+			      FUTEX_UNLOCK_PI, 0, 0);
+
+	    THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+	    return ENOTRECOVERABLE;
+	  }
+
+	mutex->__data.__count = 1;
+	if (robust)
+	  {
+	    ENQUEUE_MUTEX_PI (mutex);
+	    THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+	  }
+      }
+      break;
+
     default:
       /* Correct code cannot set any other type.  */
       return EINVAL;
diff --git a/nptl/pthread_mutex_setprioceiling.c b/nptl/pthread_mutex_setprioceiling.c
index 999b635ac1..3271f8833a 100644
--- a/nptl/pthread_mutex_setprioceiling.c
+++ b/nptl/pthread_mutex_setprioceiling.c
@@ -30,7 +30,7 @@ pthread_mutex_setprioceiling (mutex, prioceiling, old_ceiling)
 {
   /* The low bits of __kind aren't ever changed after pthread_mutex_init,
      so we don't need a lock yet.  */
-  if ((mutex->__data.__kind & PTHREAD_MUTEX_PRIO_PROTECT_PRIVATE_NP) == 0)
+  if ((mutex->__data.__kind & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0)
     return EINVAL;
 
   if (prioceiling < 0 || __builtin_expect (prioceiling > 255, 0))
diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c
index 7c48c7ce6b..12f6c997bb 100644
--- a/nptl/pthread_mutex_timedlock.c
+++ b/nptl/pthread_mutex_timedlock.c
@@ -35,7 +35,7 @@ pthread_mutex_timedlock (mutex, abstime)
   /* We must not check ABSTIME here.  If the thread does not block
      abstime must not be checked for a valid value.  */
 
-  switch (mutex->__data.__kind)
+  switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP))
     {
       /* Recursive mutex.  */
     case PTHREAD_MUTEX_RECURSIVE_NP:
@@ -65,7 +65,7 @@ pthread_mutex_timedlock (mutex, abstime)
       /* 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 */
@@ -134,7 +134,7 @@ pthread_mutex_timedlock (mutex, abstime)
 	      ENQUEUE_MUTEX (mutex);
 	      THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
 
-	      /* Note that we deliberately exist here.  If we fall
+	      /* Note that we deliberately exit here.  If we fall
 		 through to the end of the function __nusers would be
 		 incremented which is not correct because the old
 		 owner has to be discounted.  */
@@ -194,6 +194,150 @@ pthread_mutex_timedlock (mutex, abstime)
       THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
       break;
 
+    case PTHREAD_MUTEX_PI_RECURSIVE_NP:
+    case PTHREAD_MUTEX_PI_ERRORCHECK_NP:
+    case PTHREAD_MUTEX_PI_NORMAL_NP:
+    case PTHREAD_MUTEX_PI_ADAPTIVE_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP:
+      {
+	int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
+	int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
+
+	if (robust)
+	  /* Note: robust PI futexes are signaled by setting bit 0.  */
+	  THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
+			 (void *) (((uintptr_t) &mutex->__data.__list.__next)
+				   | 1));
+
+	oldval = mutex->__data.__lock;
+
+	/* Check whether we already hold the mutex.  */
+	if (__builtin_expect ((oldval & FUTEX_TID_MASK) == id, 0))
+	  {
+	    if (kind == PTHREAD_MUTEX_ERRORCHECK_NP)
+	      {
+		THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+		return EDEADLK;
+	      }
+
+	    if (kind == PTHREAD_MUTEX_RECURSIVE_NP)
+	      {
+		THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+		/* Just bump the counter.  */
+		if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
+		  /* Overflow of the counter.  */
+		  return EAGAIN;
+
+		++mutex->__data.__count;
+
+		return 0;
+	      }
+	  }
+
+	oldval = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+						      id, 0);
+
+	if (oldval != 0)
+	  {
+	    /* The mutex is locked.  The kernel will now take care of
+	       everything.  The timeout value must be a relative value.
+	       Convert it.  */
+	    INTERNAL_SYSCALL_DECL (__err);
+
+	    int e = INTERNAL_SYSCALL (futex, __err, 4, &mutex->__data.__lock,
+				      FUTEX_LOCK_PI, 1, abstime);
+	    if (INTERNAL_SYSCALL_ERROR_P (e, __err))
+	      {
+		if (INTERNAL_SYSCALL_ERRNO (e, __err) == ETIMEDOUT)
+		  return ETIMEDOUT;
+
+		if (INTERNAL_SYSCALL_ERRNO (e, __err) == ESRCH
+		    || INTERNAL_SYSCALL_ERRNO (e, __err) == EDEADLK)
+		  {
+		    assert (INTERNAL_SYSCALL_ERRNO (e, __err) != EDEADLK
+			    || (kind != PTHREAD_MUTEX_ERRORCHECK_NP
+				&& kind != PTHREAD_MUTEX_RECURSIVE_NP));
+		    /* ESRCH can happen only for non-robust PI mutexes where
+		       the owner of the lock died.  */
+		    assert (INTERNAL_SYSCALL_ERRNO (e, __err) != ESRCH
+			    || !robust);
+
+		    /* Delay the thread until the timeout is reached.
+		       Then return ETIMEDOUT.  */
+		    struct timespec reltime;
+		    struct timespec now;
+
+		    INTERNAL_SYSCALL (clock_gettime, __err, 2, CLOCK_REALTIME,
+				      &now);
+		    reltime.tv_sec = abstime->tv_sec - now.tv_sec;
+		    reltime.tv_nsec = abstime->tv_nsec - now.tv_nsec;
+		    if (reltime.tv_nsec < 0)
+		      {
+			reltime.tv_nsec += 1000000000;
+			--reltime.tv_sec;
+		      }
+		    if (reltime.tv_sec >= 0)
+		      while (__nanosleep_nocancel (&reltime, &reltime) != 0)
+			continue;
+
+		    return ETIMEDOUT;
+		  }
+
+		return INTERNAL_SYSCALL_ERRNO (e, __err);
+	      }
+
+	    oldval = mutex->__data.__lock;
+
+	    assert (robust || (oldval & FUTEX_OWNER_DIED) == 0);
+	  }
+
+	if (__builtin_expect (oldval & FUTEX_OWNER_DIED, 0))
+	  {
+	    atomic_and (&mutex->__data.__lock, ~FUTEX_OWNER_DIED);
+
+	    /* We got the mutex.  */
+	    mutex->__data.__count = 1;
+	    /* But it is inconsistent unless marked otherwise.  */
+	    mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
+
+	    ENQUEUE_MUTEX_PI (mutex);
+	    THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+	    /* Note that we deliberately exit here.  If we fall
+	       through to the end of the function __nusers would be
+	       incremented which is not correct because the old owner
+	       has to be discounted.  */
+	    return EOWNERDEAD;
+	  }
+
+	if (robust
+	    && __builtin_expect (mutex->__data.__owner
+				 == PTHREAD_MUTEX_NOTRECOVERABLE, 0))
+	  {
+	    /* This mutex is now not recoverable.  */
+	    mutex->__data.__count = 0;
+
+	    INTERNAL_SYSCALL_DECL (__err);
+	    INTERNAL_SYSCALL (futex, __err, 4, &mutex->__data.__lock,
+			      FUTEX_UNLOCK_PI, 0, 0);
+
+	    THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+	    return ENOTRECOVERABLE;
+	  }
+
+	mutex->__data.__count = 1;
+	if (robust)
+	  {
+	    ENQUEUE_MUTEX_PI (mutex);
+	    THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+	  }
+	}
+      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 148a6e919f..f3a18569a1 100644
--- a/nptl/pthread_mutex_trylock.c
+++ b/nptl/pthread_mutex_trylock.c
@@ -152,7 +152,6 @@ __pthread_mutex_trylock (mutex)
 	      return EBUSY;
 	    }
 
-	robust:
 	  if (__builtin_expect (mutex->__data.__owner
 				== PTHREAD_MUTEX_NOTRECOVERABLE, 0))
 	    {
@@ -175,6 +174,129 @@ __pthread_mutex_trylock (mutex)
 
       return 0;
 
+    case PTHREAD_MUTEX_PI_RECURSIVE_NP:
+    case PTHREAD_MUTEX_PI_ERRORCHECK_NP:
+    case PTHREAD_MUTEX_PI_NORMAL_NP:
+    case PTHREAD_MUTEX_PI_ADAPTIVE_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP:
+      {
+	int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
+	int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
+
+	if (robust)
+	  /* Note: robust PI futexes are signaled by setting bit 0.  */
+	  THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
+			 (void *) (((uintptr_t) &mutex->__data.__list.__next)
+				   | 1));
+
+	oldval = mutex->__data.__lock;
+
+	/* Check whether we already hold the mutex.  */
+	if (__builtin_expect ((oldval & FUTEX_TID_MASK) == id, 0))
+	  {
+	    if (kind == PTHREAD_MUTEX_ERRORCHECK_NP)
+	      {
+		THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+		return EDEADLK;
+	      }
+
+	    if (kind == PTHREAD_MUTEX_RECURSIVE_NP)
+	      {
+		THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+		/* Just bump the counter.  */
+		if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
+		  /* Overflow of the counter.  */
+		  return EAGAIN;
+
+		++mutex->__data.__count;
+
+		return 0;
+	      }
+	  }
+
+	oldval
+	  = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+						 id, 0);
+
+	if (oldval != 0)
+	  {
+	    if ((oldval & FUTEX_OWNER_DIED) == 0)
+	      {
+		THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+		return EBUSY;
+	      }
+
+	    assert (robust);
+
+	    /* The mutex owner died.  The kernel will now take care of
+	       everything.  */
+	    INTERNAL_SYSCALL_DECL (__err);
+	    int e = INTERNAL_SYSCALL (futex, __err, 4, &mutex->__data.__lock,
+				      FUTEX_TRYLOCK_PI, 0, 0);
+
+	    if (INTERNAL_SYSCALL_ERROR_P (e, __err)
+		&& INTERNAL_SYSCALL_ERRNO (e, __err) == EWOULDBLOCK)
+	      {
+		THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+		return EBUSY;
+	      }
+
+	    oldval = mutex->__data.__lock;
+	  }
+
+	if (__builtin_expect (oldval & FUTEX_OWNER_DIED, 0))
+	  {
+	    atomic_and (&mutex->__data.__lock, ~FUTEX_OWNER_DIED);
+
+	    /* We got the mutex.  */
+	    mutex->__data.__count = 1;
+	    /* But it is inconsistent unless marked otherwise.  */
+	    mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
+
+	    ENQUEUE_MUTEX (mutex);
+	    THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+	    /* Note that we deliberately exit here.  If we fall
+	       through to the end of the function __nusers would be
+	       incremented which is not correct because the old owner
+	       has to be discounted.  */
+	    return EOWNERDEAD;
+	  }
+
+	if (robust
+	    && __builtin_expect (mutex->__data.__owner
+				 == PTHREAD_MUTEX_NOTRECOVERABLE, 0))
+	  {
+	    /* This mutex is now not recoverable.  */
+	    mutex->__data.__count = 0;
+
+	    INTERNAL_SYSCALL_DECL (__err);
+	    INTERNAL_SYSCALL (futex, __err, 4, &mutex->__data.__lock,
+			      FUTEX_UNLOCK_PI, 0, 0);
+
+	    THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+	    return ENOTRECOVERABLE;
+	  }
+
+	if (robust)
+	  {
+	    ENQUEUE_MUTEX_PI (mutex);
+	    THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+	  }
+
+	mutex->__data.__owner = id;
+	++mutex->__data.__nusers;
+	mutex->__data.__count = 1;
+
+	return 0;
+      }
+
     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 bf9aa7625f..2b5064fbac 100644
--- a/nptl/pthread_mutex_unlock.c
+++ b/nptl/pthread_mutex_unlock.c
@@ -119,6 +119,89 @@ __pthread_mutex_unlock_usercnt (mutex, decr)
       THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
       break;
 
+    case PTHREAD_MUTEX_PI_RECURSIVE_NP:
+      /* Recursive mutex.  */
+      if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid))
+	return EPERM;
+
+      if (--mutex->__data.__count != 0)
+	/* We still hold the mutex.  */
+	return 0;
+      goto continue_pi;
+
+    case PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP:
+      /* Recursive mutex.  */
+      if ((mutex->__data.__lock & FUTEX_TID_MASK)
+	  == THREAD_GETMEM (THREAD_SELF, tid)
+	  && __builtin_expect (mutex->__data.__owner
+			       == PTHREAD_MUTEX_INCONSISTENT, 0))
+	{
+	  if (--mutex->__data.__count != 0)
+	    /* We still hold the mutex.  */
+	    return ENOTRECOVERABLE;
+
+	  goto pi_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 continue_pi;
+
+    case PTHREAD_MUTEX_PI_ERRORCHECK_NP:
+    case PTHREAD_MUTEX_PI_NORMAL_NP:
+    case PTHREAD_MUTEX_PI_ADAPTIVE_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP:
+    case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP:
+      if ((mutex->__data.__lock & FUTEX_TID_MASK)
+	  != THREAD_GETMEM (THREAD_SELF, tid)
+	  || ! lll_mutex_islocked (mutex->__data.__lock))
+	return EPERM;
+
+      /* 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 ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0
+	  && __builtin_expect (mutex->__data.__owner
+			       == PTHREAD_MUTEX_INCONSISTENT, 0))
+      pi_notrecoverable:
+       newowner = PTHREAD_MUTEX_NOTRECOVERABLE;
+
+    continue_pi:
+      if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0)
+	{
+	  /* Remove mutex from the list.
+	     Note: robust PI futexes are signaled by setting bit 0.  */
+	  THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
+			 (void *) (((uintptr_t) &mutex->__data.__list.__next)
+				   | 1));
+	  DEQUEUE_MUTEX (mutex);
+	}
+
+      mutex->__data.__owner = newowner;
+      if (decr)
+	/* One less user.  */
+	--mutex->__data.__nusers;
+
+      /* Unlock.  */
+      if ((mutex->__data.__lock & FUTEX_WAITERS) != 0
+	  || atomic_compare_and_exchange_bool_acq (&mutex->__data.__lock, 0,
+						   THREAD_GETMEM (THREAD_SELF,
+								  tid)))
+	{
+	  INTERNAL_SYSCALL_DECL (__err);
+	  INTERNAL_SYSCALL (futex, __err, 2, &mutex->__data.__lock,
+			    FUTEX_UNLOCK_PI);
+	}
+
+      THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+      break;
+
     default:
       /* Correct code cannot set any other type.  */
       return EINVAL;
diff --git a/nptl/sysdeps/pthread/pthread_cond_broadcast.c b/nptl/sysdeps/pthread/pthread_cond_broadcast.c
index 1eac8ecf83..2b8b5460f4 100644
--- a/nptl/sysdeps/pthread/pthread_cond_broadcast.c
+++ b/nptl/sysdeps/pthread/pthread_cond_broadcast.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
 
@@ -55,6 +55,12 @@ __pthread_cond_broadcast (cond)
 
       /* Wake everybody.  */
       pthread_mutex_t *mut = (pthread_mutex_t *) cond->__data.__mutex;
+
+      /* XXX: Kernel so far doesn't support requeue to PI futex.  */
+      if (__builtin_expect (mut->__data.__kind & PTHREAD_MUTEX_PRIO_INHERIT_NP,
+			    0))
+	goto wake_all;
+
       /* lll_futex_requeue returns 0 for success and non-zero
 	 for errors.  */
       if (__builtin_expect (lll_futex_requeue (&cond->__data.__futex, 1,
diff --git a/nptl/sysdeps/unix/sysv/linux/Makefile b/nptl/sysdeps/unix/sysv/linux/Makefile
index 88dce1a886..cfcdb6d97f 100644
--- a/nptl/sysdeps/unix/sysv/linux/Makefile
+++ b/nptl/sysdeps/unix/sysv/linux/Makefile
@@ -25,7 +25,7 @@ libpthread-sysdep_routines += pt-fork pthread_mutex_cond_lock
 
 gen-as-const-headers += lowlevelcond.sym lowlevelrwlock.sym \
 			lowlevelbarrier.sym unwindbuf.sym \
-			lowlevelrobustlock.sym
+			lowlevelrobustlock.sym pthread-pi-defines.sym
 endif
 
 ifeq ($(subdir),posix)
diff --git a/nptl/sysdeps/unix/sysv/linux/alpha/lowlevellock.h b/nptl/sysdeps/unix/sysv/linux/alpha/lowlevellock.h
index 1a2e8cbb07..58b4806eb2 100644
--- a/nptl/sysdeps/unix/sysv/linux/alpha/lowlevellock.h
+++ b/nptl/sysdeps/unix/sysv/linux/alpha/lowlevellock.h
@@ -33,6 +33,9 @@
 #define FUTEX_CMP_REQUEUE	4
 #define FUTEX_WAKE_OP		5
 #define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE	((4 << 24) | 1)
+#define FUTEX_LOCK_PI		6
+#define FUTEX_UNLOCK_PI		7
+#define FUTEX_TRYLOCK_PI	8
 
 /* Initializer for compatibility lock.	*/
 #define LLL_MUTEX_LOCK_INITIALIZER (0)
diff --git a/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h b/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h
index 92c2d32827..d8eced1f22 100644
--- a/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h
+++ b/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h
@@ -1,5 +1,5 @@
 /* Define POSIX options for Linux.
-   Copyright (C) 1996-2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 1996-2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -79,6 +79,9 @@
 /* We support user-defined stacks.  */
 #define _POSIX_THREAD_ATTR_STACKADDR	200112L
 
+/* We support priority inheritence.  */
+#define _POSIX_THREAD_PRIO_INHERIT	200112L
+
 /* We support POSIX.1b semaphores.  */
 #define _POSIX_SEMAPHORES	200112L
 
@@ -171,8 +174,7 @@
 /* Typed memory objects are not available.  */
 #define _POSIX_TYPED_MEMORY_OBJECTS	-1
 
-/* No support for priority inheritance or protection so far.  */
-#define _POSIX_THREAD_PRIO_INHERIT	-1
+/* No support for priority protection so far.  */
 #define _POSIX_THREAD_PRIO_PROTECT	-1
 
 #endif /* posix_opt.h */
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S
index 5471c1c927..56f7be8246 100644
--- a/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -21,6 +21,7 @@
 #include <shlib-compat.h>
 #include <lowlevelcond.h>
 #include <kernel-features.h>
+#include <pthread-pi-defines.h>
 
 #ifdef UP
 # define LOCK
@@ -94,6 +95,10 @@ __pthread_cond_broadcast:
 8:	cmpl	$-1, %edi
 	je	9f
 
+	/* XXX: The kernel so far doesn't support requeue to PI futex.  */
+	testl	$PI_BIT, MUTEX_KIND(%edi)
+	jne	9f
+
 	/* Wake up all threads.  */
 	movl	$FUTEX_CMP_REQUEUE, %ecx
 	movl	$SYS_futex, %eax
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h b/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h
index e405f84f25..64088ef732 100644
--- a/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h
+++ b/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h
@@ -35,6 +35,9 @@
 #define SYS_futex		240
 #define FUTEX_WAIT		0
 #define FUTEX_WAKE		1
+#define FUTEX_LOCK_PI		6
+#define FUTEX_UNLOCK_PI		7
+#define FUTEX_TRYLOCK_PI	8
 
 
 /* Initializer for compatibility lock.  */
diff --git a/nptl/sysdeps/unix/sysv/linux/ia64/lowlevellock.h b/nptl/sysdeps/unix/sysv/linux/ia64/lowlevellock.h
index ece9a7fc72..8df997a262 100644
--- a/nptl/sysdeps/unix/sysv/linux/ia64/lowlevellock.h
+++ b/nptl/sysdeps/unix/sysv/linux/ia64/lowlevellock.h
@@ -33,6 +33,9 @@
 #define FUTEX_CMP_REQUEUE	4
 #define FUTEX_WAKE_OP		5
 #define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE	((4 << 24) | 1)
+#define FUTEX_LOCK_PI		6
+#define FUTEX_UNLOCK_PI		7
+#define FUTEX_TRYLOCK_PI	8
 
 /* Delay in spinlock loop.  */
 #define BUSY_WAIT_NOP          asm ("hint @pause")
diff --git a/nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h b/nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h
index abd019df47..0136b97595 100644
--- a/nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h
+++ b/nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h
@@ -35,6 +35,9 @@
 #define FUTEX_CMP_REQUEUE	4
 #define FUTEX_WAKE_OP		5
 #define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE	((4 << 24) | 1)
+#define FUTEX_LOCK_PI		6
+#define FUTEX_UNLOCK_PI		7
+#define FUTEX_TRYLOCK_PI	8
 
 /* Initializer for compatibility lock.	*/
 #define LLL_MUTEX_LOCK_INITIALIZER (0)
diff --git a/nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym b/nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym
new file mode 100644
index 0000000000..a1b6794260
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym
@@ -0,0 +1,6 @@
+#include <pthreadP.h>
+
+-- These PI macros are used by assembly code.
+
+MUTEX_KIND	offsetof (pthread_mutex_t, __data.__kind)
+PI_BIT		PTHREAD_MUTEX_PRIO_INHERIT_NP
diff --git a/nptl/sysdeps/unix/sysv/linux/s390/lowlevellock.h b/nptl/sysdeps/unix/sysv/linux/s390/lowlevellock.h
index 6baab90f56..38d9f2ac41 100644
--- a/nptl/sysdeps/unix/sysv/linux/s390/lowlevellock.h
+++ b/nptl/sysdeps/unix/sysv/linux/s390/lowlevellock.h
@@ -32,6 +32,9 @@
 #define FUTEX_CMP_REQUEUE	4
 #define FUTEX_WAKE_OP		5
 #define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE	((4 << 24) | 1)
+#define FUTEX_LOCK_PI		6
+#define FUTEX_UNLOCK_PI		7
+#define FUTEX_TRYLOCK_PI	8
 
 /* Initializer for compatibility lock.	*/
 #define LLL_MUTEX_LOCK_INITIALIZER (0)
diff --git a/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.h b/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.h
index 92f93cd5f5..0eb1f0114c 100644
--- a/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.h
+++ b/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.h
@@ -26,6 +26,9 @@
 #define SYS_futex		240
 #define FUTEX_WAIT		0
 #define FUTEX_WAKE		1
+#define FUTEX_LOCK_PI		6
+#define FUTEX_UNLOCK_PI		7
+#define FUTEX_TRYLOCK_PI	8
 
 
 /* Initializer for compatibility lock.  */
diff --git a/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.h b/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.h
index 77eefc546c..5013922a2f 100644
--- a/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.h
+++ b/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.h
@@ -32,6 +32,9 @@
 #define FUTEX_CMP_REQUEUE	4
 #define FUTEX_WAKE_OP		5
 #define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE	((4 << 24) | 1)
+#define FUTEX_LOCK_PI		6
+#define FUTEX_UNLOCK_PI		7
+#define FUTEX_TRYLOCK_PI	8
 
 /* Initializer for compatibility lock.	*/
 #define LLL_MUTEX_LOCK_INITIALIZER (0)
diff --git a/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h b/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h
index 5047e4fe4d..7da2f12231 100644
--- a/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h
+++ b/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h
@@ -35,6 +35,9 @@
 #define SYS_futex		202
 #define FUTEX_WAIT		0
 #define FUTEX_WAKE		1
+#define FUTEX_LOCK_PI		6
+#define FUTEX_UNLOCK_PI		7
+#define FUTEX_TRYLOCK_PI	8
 
 
 /* Initializer for compatibility lock.  */
diff --git a/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S b/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S
index 72e7bc5b24..006de2696e 100644
--- a/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S
+++ b/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -21,6 +21,7 @@
 #include <shlib-compat.h>
 #include <lowlevelcond.h>
 #include <kernel-features.h>
+#include <pthread-pi-defines.h>
 
 #ifdef UP
 # define LOCK
@@ -80,6 +81,10 @@ __pthread_cond_broadcast:
 8:	cmpq	$-1, %r8
 	je	9f
 
+	/* XXX: The kernel so far doesn't support requeue to PI futex.  */
+	testl	$PI_BIT, MUTEX_KIND(%r8)
+	jne	9f
+
 	/* Wake up all threads.  */
 	movl	$FUTEX_CMP_REQUEUE, %esi
 	movl	$SYS_futex, %eax
diff --git a/nptl/tst-mutex1.c b/nptl/tst-mutex1.c
index 50b5ccaf0e..c3ef5b2b51 100644
--- a/nptl/tst-mutex1.c
+++ b/nptl/tst-mutex1.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -19,6 +19,12 @@
 
 #include <pthread.h>
 #include <stdio.h>
+#include <errno.h>
+
+
+#ifndef ATTR
+# define ATTR NULL
+#endif
 
 
 static int
@@ -26,12 +32,24 @@ do_test (void)
 {
   pthread_mutex_t m;
 
-  if (pthread_mutex_init (&m, NULL) != 0)
+  int e = pthread_mutex_init (&m, ATTR);
+  if (ATTR != NULL && e == ENOTSUP)
+    {
+      puts ("cannot support selected type of mutexes");
+      return 0;
+    }
+  else if (e != 0)
     {
       puts ("mutex_init failed");
       return 1;
     }
 
+  if (ATTR != NULL && pthread_mutexattr_destroy (ATTR) != 0)
+    {
+      puts ("mutexattr_destroy failed");
+      return 1;
+    }
+
   if (pthread_mutex_lock (&m) != 0)
     {
       puts ("mutex_lock failed");
diff --git a/nptl/tst-mutex2.c b/nptl/tst-mutex2.c
index f589a1ea17..b09f569a5a 100644
--- a/nptl/tst-mutex2.c
+++ b/nptl/tst-mutex2.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -105,115 +105,134 @@ do_test (void)
   if (pthread_mutexattr_init (&a) != 0)
     {
       puts ("mutexattr_init failed");
-      exit (1);
+      return 1;
     }
 
   if (pthread_mutexattr_settype (&a, PTHREAD_MUTEX_ERRORCHECK) != 0)
     {
       puts ("mutexattr_settype failed");
-      exit (1);
+      return 1;
     }
 
-  if (pthread_mutex_init (&m, &a) != 0)
+#ifdef ENABLE_PI
+  if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0)
     {
+      puts ("pthread_mutexattr_setprotocol failed");
+      return 1;
+    }
+#endif
+
+  e = pthread_mutex_init (&m, &a);
+  if (e != 0)
+    {
+#ifdef ENABLE_PI
+      if (e == ENOTSUP)
+	{
+	  puts ("PI mutexes unsupported");
+	  return 0;
+	}
+#endif
       puts ("mutex_init failed");
-      exit (1);
+      return 1;
     }
 
   if (pthread_barrier_init (&b, NULL, 2) != 0)
     {
       puts ("barrier_init failed");
-      exit (1);
+      return 1;
     }
 
-  if ((e = pthread_mutex_unlock (&m)) == 0)
+  e = pthread_mutex_unlock (&m);
+  if (e == 0)
     {
       puts ("1st mutex_unlock succeeded");
-      exit (1);
+      return 1;
     }
   else if (e != EPERM)
     {
       puts ("1st mutex_unlock error != EPERM");
-      exit (1);
+      return 1;
     }
 
   if (pthread_mutex_lock (&m) != 0)
     {
       puts ("mutex_lock failed");
-      exit (1);
+      return 1;
     }
 
-  if ((e = pthread_mutex_lock (&m)) == 0)
+  e = pthread_mutex_lock (&m);
+  if (e == 0)
     {
       puts ("2nd mutex_lock succeeded");
-      exit (1);
+      return 1;
     }
   else if (e != EDEADLK)
     {
       puts ("2nd mutex_lock error != EDEADLK");
-      exit (1);
+      return 1;
     }
 
   pthread_t th;
   if (pthread_create (&th, NULL, tf, NULL) != 0)
     {
       puts ("create failed");
-      exit (1);
+      return 1;
     }
 
   e = pthread_barrier_wait (&b);
   if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
     {
       puts ("1st barrier_wait failed");
-      exit (1);
+      return 1;
     }
 
   if (pthread_mutex_unlock (&m) != 0)
     {
       puts ("2nd mutex_unlock failed");
-      exit (1);
+      return 1;
     }
 
-  if ((e = pthread_mutex_unlock (&m)) == 0)
+  e = pthread_mutex_unlock (&m);
+  if (e == 0)
     {
       puts ("3rd mutex_unlock succeeded");
-      exit (1);
+      return 1;
     }
   else if (e != EPERM)
     {
       puts ("3rd mutex_unlock error != EPERM");
-      exit (1);
+      return 1;
     }
 
   e = pthread_barrier_wait (&b);
   if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
     {
       puts ("2nd barrier_wait failed");
-      exit (1);
+      return 1;
     }
 
   if (pthread_join (th, NULL) != 0)
     {
       puts ("join failed");
-      exit (1);
+      return 1;
     }
 
   if (pthread_mutex_destroy (&m) != 0)
     {
       puts ("mutex_destroy failed");
-      exit (1);
+      return 1;
     }
 
   if (pthread_barrier_destroy (&b) != 0)
     {
       puts ("barrier_destroy failed");
-      exit (1);
+      return 1;
     }
 
   if (pthread_mutexattr_destroy (&a) != 0)
     {
       puts ("mutexattr_destroy failed");
-      exit (1);
+      return 1;
     }
 
   return 0;
diff --git a/nptl/tst-mutex3.c b/nptl/tst-mutex3.c
index 8e57924ba6..2848096538 100644
--- a/nptl/tst-mutex3.c
+++ b/nptl/tst-mutex3.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -113,8 +113,25 @@ do_test (void)
       return 1;
     }
 
-  if (pthread_mutex_init (&m, &a) != 0)
+#ifdef ENABLE_PI
+  if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0)
     {
+      puts ("pthread_mutexattr_setprotocol failed");
+      return 1;
+    }
+#endif
+
+  int e;
+  e = pthread_mutex_init (&m, &a);
+  if (e != 0)
+    {
+#ifdef ENABLE_PI
+      if (e == ENOTSUP)
+	{
+	  puts ("PI mutexes unsupported");
+	  return 0;
+	}
+#endif
       puts ("mutex_init failed");
       return 1;
     }
@@ -162,7 +179,7 @@ do_test (void)
       return 1;
     }
 
-  int e = pthread_barrier_wait (&b);
+  e = pthread_barrier_wait (&b);
   if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
     {
       puts ("barrier_wait failed");
diff --git a/nptl/tst-mutex4.c b/nptl/tst-mutex4.c
index 0ce7313caf..9699c2db45 100644
--- a/nptl/tst-mutex4.c
+++ b/nptl/tst-mutex4.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -42,6 +42,8 @@ do_test (void)
   char *p;
   int err;
   int s;
+  pthread_barrier_t *b;
+  pthread_barrierattr_t ba;
 
   fd = mkstemp (tmpfname);
   if (fd == -1)
@@ -70,9 +72,12 @@ do_test (void)
       return 1;
     }
 
-  m = (pthread_mutex_t *) (((uintptr_t) mem + __alignof (pthread_mutex_t))
+  m = (pthread_mutex_t *) (((uintptr_t) mem + __alignof (pthread_mutex_t) - 1)
 			   & ~(__alignof (pthread_mutex_t) - 1));
-  p = (char *) (m + 1);
+  b = (pthread_barrier_t *) (((uintptr_t) (m + 1)
+			      + __alignof (pthread_barrier_t) - 1)
+			     & ~(__alignof (pthread_barrier_t) - 1));
+  p = (char *) (b + 1);
 
   if (pthread_mutexattr_init (&a) != 0)
     {
@@ -110,8 +115,23 @@ do_test (void)
       return 1;
     }
 
-  if (pthread_mutex_init (m, &a) != 0)
+#ifdef ENABLE_PI
+  if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0)
     {
+      puts ("pthread_mutexattr_setprotocol failed");
+      return 1;
+    }
+#endif
+
+  if ((err = pthread_mutex_init (m, &a)) != 0)
+    {
+#ifdef ENABLE_PI
+      if (err == ENOTSUP)
+	{
+	  puts ("PI mutexes unsupported");
+	  return 0;
+	}
+#endif
       puts ("mutex_init failed");
       return 1;
     }
@@ -128,6 +148,30 @@ do_test (void)
       return 1;
     }
 
+  if (pthread_barrierattr_init (&ba) != 0)
+    {
+      puts ("barrierattr_init failed");
+      return 1;
+    }
+
+  if (pthread_barrierattr_setpshared (&ba, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("barrierattr_setpshared failed");
+      return 1;
+    }
+
+  if (pthread_barrier_init (b, &ba, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  if (pthread_barrierattr_destroy (&ba) != 0)
+    {
+      puts ("barrierattr_destroy failed");
+      return 1;
+    }
+
   err = pthread_mutex_trylock (m);
   if (err == 0)
     {
@@ -142,6 +186,12 @@ do_test (void)
 
   *p = 0;
 
+  if (pthread_mutex_unlock (m) != 0)
+    {
+      puts ("parent: 1st mutex_unlock failed");
+      return 1;
+    }
+
   puts ("going to fork now");
   pid = fork ();
   if (pid == -1)
@@ -151,7 +201,19 @@ do_test (void)
     }
   else if (pid == 0)
     {
-      /* Play some lock ping-pong.  It's our turn to unlock first.  */
+      if (pthread_mutex_lock (m) != 0)
+	{
+	  puts ("child: mutex_lock failed");
+	  return 1;
+	}
+
+      int e = pthread_barrier_wait (b);
+      if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  puts ("child: barrier_wait failed");
+	  return 1;
+	}
+
       if ((*p)++ != 0)
 	{
 	  puts ("child: *p != 0");
@@ -160,7 +222,7 @@ do_test (void)
 
       if (pthread_mutex_unlock (m) != 0)
 	{
-	  puts ("child: 1st mutex_unlock failed");
+	  puts ("child: mutex_unlock failed");
 	  return 1;
 	}
 
@@ -168,6 +230,13 @@ do_test (void)
     }
   else
     {
+      int e = pthread_barrier_wait (b);
+      if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  puts ("parent: barrier_wait failed");
+	  return 1;
+	}
+
       if (pthread_mutex_lock (m) != 0)
 	{
 	  puts ("parent: 2nd mutex_lock failed");
@@ -180,6 +249,24 @@ do_test (void)
 	  return 1;
 	}
 
+      if (pthread_mutex_unlock (m) != 0)
+	{
+	  puts ("parent: 2nd mutex_unlock failed");
+	  return 1;
+	}
+
+      if (pthread_mutex_destroy (m) != 0)
+	{
+	  puts ("mutex_destroy failed");
+	  return 1;
+	}
+
+      if (pthread_barrier_destroy (b) != 0)
+	{
+	  puts ("barrier_destroy failed");
+	  return 1;
+	}
+
       puts ("parent done");
     }
 
diff --git a/nptl/tst-mutex5.c b/nptl/tst-mutex5.c
index eb35b78d36..291274fee5 100644
--- a/nptl/tst-mutex5.c
+++ b/nptl/tst-mutex5.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -52,8 +52,24 @@ do_test (void)
       return 1;
     }
 
-  if (pthread_mutex_init (&m, &a) != 0)
+#ifdef ENABLE_PI
+  if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0)
     {
+      puts ("pthread_mutexattr_setprotocol failed");
+      return 1;
+    }
+#endif
+
+  err = pthread_mutex_init (&m, &a);
+  if (err != 0)
+    {
+#ifdef ENABLE_PI
+      if (err == ENOTSUP)
+	{
+	  puts ("PI mutexes unsupported");
+	  return 0;
+	}
+#endif
       puts ("mutex_init failed");
       return 1;
     }
diff --git a/nptl/tst-mutex6.c b/nptl/tst-mutex6.c
index f066c62edc..e5698c3eb0 100644
--- a/nptl/tst-mutex6.c
+++ b/nptl/tst-mutex6.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -21,6 +21,12 @@
 #include <signal.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <errno.h>
+
+
+#ifndef ATTR
+# define ATTR NULL
+#endif
 
 
 static int
@@ -28,12 +34,24 @@ do_test (void)
 {
   pthread_mutex_t m;
 
-  if (pthread_mutex_init (&m, NULL) != 0)
+  int e = pthread_mutex_init (&m, ATTR);
+  if (ATTR != NULL && e == ENOTSUP)
+    {
+      puts ("cannot support selected type of mutexes");
+      e = pthread_mutex_init (&m, NULL);
+    }
+  if (e != 0)
     {
       puts ("mutex_init failed");
       return 1;
     }
 
+  if (ATTR != NULL && pthread_mutexattr_destroy (ATTR) != 0)
+    {
+      puts ("mutexattr_destroy failed");
+      return 1;
+    }
+
   if (pthread_mutex_lock (&m) != 0)
     {
       puts ("1st mutex_lock failed");
diff --git a/nptl/tst-mutex7.c b/nptl/tst-mutex7.c
index a9b9f318cb..27e5d8eb28 100644
--- a/nptl/tst-mutex7.c
+++ b/nptl/tst-mutex7.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -17,17 +17,19 @@
    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>
 #include <time.h>
 
 
-#ifndef INIT
-# define INIT PTHREAD_MUTEX_INITIALIZER
+#ifndef TYPE
+# define TYPE PTHREAD_MUTEX_DEFAULT
 #endif
 
 
-static pthread_mutex_t lock = INIT;
+static pthread_mutex_t lock;
 
 
 #define ROUNDS 1000
@@ -65,6 +67,48 @@ tf (void *arg)
 static int
 do_test (void)
 {
+  pthread_mutexattr_t a;
+
+  if (pthread_mutexattr_init (&a) != 0)
+    {
+      puts ("mutexattr_init failed");
+      exit (1);
+    }
+
+  if (pthread_mutexattr_settype (&a, TYPE) != 0)
+    {
+      puts ("mutexattr_settype failed");
+      exit (1);
+    }
+
+#ifdef ENABLE_PI
+  if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0)
+    {
+      puts ("pthread_mutexattr_setprotocol failed");
+      return 1;
+    }
+#endif
+
+  int e = pthread_mutex_init (&lock, &a);
+  if (e != 0)
+    {
+#ifdef ENABLE_PI
+      if (e == ENOTSUP)
+	{
+	  puts ("PI mutexes unsupported");
+	  return 0;
+	}
+#endif
+      puts ("mutex_init failed");
+      return 1;
+    }
+
+  if (pthread_mutexattr_destroy (&a) != 0)
+    {
+      puts ("mutexattr_destroy failed");
+      return 1;
+    }
+
   pthread_attr_t at;
   pthread_t th[N];
   int cnt;
diff --git a/nptl/tst-mutex7a.c b/nptl/tst-mutex7a.c
index f08799ae79..30d46b81af 100644
--- a/nptl/tst-mutex7a.c
+++ b/nptl/tst-mutex7a.c
@@ -1,2 +1,2 @@
-#define INIT PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
+#define TYPE PTHREAD_MUTEX_ADAPTIVE_NP
 #include "tst-mutex7.c"
diff --git a/nptl/tst-mutex9.c b/nptl/tst-mutex9.c
index 5ea2f0ac99..f9d379343d 100644
--- a/nptl/tst-mutex9.c
+++ b/nptl/tst-mutex9.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+/* Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
 
@@ -88,8 +88,24 @@ do_test (void)
       return 1;
     }
 
-  if (pthread_mutex_init (m, &a) != 0)
+#ifdef ENABLE_PI
+  if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0)
     {
+      puts ("pthread_mutexattr_setprotocol failed");
+      return 1;
+    }
+#endif
+
+  int e;
+  if ((e = pthread_mutex_init (m, &a)) != 0)
+    {
+#ifdef ENABLE_PI
+      if (e == ENOTSUP)
+	{
+	  puts ("PI mutexes unsupported");
+	  return 0;
+	}
+#endif
       puts ("mutex_init failed");
       return 1;
     }
@@ -138,7 +154,7 @@ do_test (void)
 	  ts.tv_nsec -= 1000000000;
 	}
 
-      int e = pthread_mutex_timedlock (m, &ts);
+      e = pthread_mutex_timedlock (m, &ts);
       if (e == 0)
 	{
 	  puts ("child: mutex_timedlock succeeded");
diff --git a/nptl/tst-mutexpi1.c b/nptl/tst-mutexpi1.c
new file mode 100644
index 0000000000..623ede9fa5
--- /dev/null
+++ b/nptl/tst-mutexpi1.c
@@ -0,0 +1,27 @@
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static pthread_mutexattr_t a;
+
+static void
+prepare (void)
+{
+  if (pthread_mutexattr_init (&a) != 0)
+    {
+      puts ("mutexattr_init failed");
+      exit (1);
+    }
+
+  if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0)
+    {
+      puts ("mutexattr_setprotocol failed");
+      exit (1);
+    }
+}
+#define PREPARE(argc, argv) prepare ()
+
+
+#define ATTR &a
+#include "tst-mutex1.c"
diff --git a/nptl/tst-mutexpi2.c b/nptl/tst-mutexpi2.c
new file mode 100644
index 0000000000..fbe48716fd
--- /dev/null
+++ b/nptl/tst-mutexpi2.c
@@ -0,0 +1,2 @@
+#define ENABLE_PI 1
+#include "tst-mutex2.c"
diff --git a/nptl/tst-mutexpi3.c b/nptl/tst-mutexpi3.c
new file mode 100644
index 0000000000..e338ebfff9
--- /dev/null
+++ b/nptl/tst-mutexpi3.c
@@ -0,0 +1,2 @@
+#define ENABLE_PI 1
+#include "tst-mutex3.c"
diff --git a/nptl/tst-mutexpi4.c b/nptl/tst-mutexpi4.c
new file mode 100644
index 0000000000..177b17b475
--- /dev/null
+++ b/nptl/tst-mutexpi4.c
@@ -0,0 +1,2 @@
+#define ENABLE_PI 1
+#include "tst-mutex4.c"
diff --git a/nptl/tst-mutexpi5.c b/nptl/tst-mutexpi5.c
new file mode 100644
index 0000000000..287465c23f
--- /dev/null
+++ b/nptl/tst-mutexpi5.c
@@ -0,0 +1,2 @@
+#define ENABLE_PI 1
+#include "tst-mutex5.c"
diff --git a/nptl/tst-mutexpi5a.c b/nptl/tst-mutexpi5a.c
new file mode 100644
index 0000000000..2f85c94ff3
--- /dev/null
+++ b/nptl/tst-mutexpi5a.c
@@ -0,0 +1,2 @@
+#define ENABLE_PI 1
+#include "tst-mutex5a.c"
diff --git a/nptl/tst-mutexpi6.c b/nptl/tst-mutexpi6.c
new file mode 100644
index 0000000000..42cda377d1
--- /dev/null
+++ b/nptl/tst-mutexpi6.c
@@ -0,0 +1,27 @@
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static pthread_mutexattr_t a;
+
+static void
+prepare (void)
+{
+  if (pthread_mutexattr_init (&a) != 0)
+    {
+      puts ("mutexattr_init failed");
+      exit (1);
+    }
+
+  if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0)
+    {
+      puts ("mutexattr_setprotocol failed");
+      exit (1);
+    }
+}
+#define PREPARE(argc, argv) prepare ()
+
+
+#define ATTR &a
+#include "tst-mutex6.c"
diff --git a/nptl/tst-mutexpi7.c b/nptl/tst-mutexpi7.c
new file mode 100644
index 0000000000..1e7e929380
--- /dev/null
+++ b/nptl/tst-mutexpi7.c
@@ -0,0 +1,2 @@
+#define ENABLE_PI 1
+#include "tst-mutex7.c"
diff --git a/nptl/tst-mutexpi7a.c b/nptl/tst-mutexpi7a.c
new file mode 100644
index 0000000000..c59083cf6e
--- /dev/null
+++ b/nptl/tst-mutexpi7a.c
@@ -0,0 +1,2 @@
+#define ENABLE_PI 1
+#include "tst-mutex7a.c"
diff --git a/nptl/tst-mutexpi8.c b/nptl/tst-mutexpi8.c
new file mode 100644
index 0000000000..cea60309a8
--- /dev/null
+++ b/nptl/tst-mutexpi8.c
@@ -0,0 +1,2 @@
+#define ENABLE_PI 1
+#include "tst-mutex8.c"
diff --git a/nptl/tst-mutexpi9.c b/nptl/tst-mutexpi9.c
new file mode 100644
index 0000000000..3710d9e080
--- /dev/null
+++ b/nptl/tst-mutexpi9.c
@@ -0,0 +1,2 @@
+#define ENABLE_PI 1
+#include "tst-mutex9.c"
diff --git a/nptl/tst-robust1.c b/nptl/tst-robust1.c
index 9806ca467a..bc48700e4a 100644
--- a/nptl/tst-robust1.c
+++ b/nptl/tst-robust1.c
@@ -97,6 +97,30 @@ do_test (void)
       puts ("mutexattr_setrobust failed");
       return 1;
     }
+
+#ifdef ENABLE_PI
+  if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0)
+    {
+      puts ("pthread_mutexattr_setprotocol failed");
+      return 1;
+    }
+  else
+    {
+      int e = pthread_mutex_init (&m1, &a);
+      if (e == ENOTSUP)
+	{
+	  puts ("PI robust mutexes not supported");
+	  return 0;
+	}
+      else if (e != 0)
+	{
+	  puts ("mutex_init m1 failed");
+	  return 1;
+	}
+      pthread_mutex_destroy (&m1);
+    }
+#endif
+
 #ifndef NOT_CONSISTENT
   if (pthread_mutex_init (&m1, &a) != 0)
     {
@@ -236,14 +260,14 @@ do_test (void)
       e = pthread_mutex_unlock (&m1);
       if (e != 0)
 	{
-	  printf ("%ld: mutex_unlock m1 failed\n", round);
+	  printf ("%ld: mutex_unlock m1 failed with %d\n", round, e);
 	  return 1;
 	}
 
       e = pthread_mutex_unlock (&m2);
       if (e != 0)
 	{
-	  printf ("%ld: mutex_unlock m2 failed\n", round);
+	  printf ("%ld: mutex_unlock m2 failed with %d\n", round, e);
 	  return 1;
 	}
 
diff --git a/nptl/tst-robust7.c b/nptl/tst-robust7.c
index 2c5acb44ce..d0bc91cc8e 100644
--- a/nptl/tst-robust7.c
+++ b/nptl/tst-robust7.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2005.
 
@@ -95,8 +95,25 @@ do_test (void)
       return 1;
     }
 
-  if (pthread_mutex_init (&m, &a) != 0)
+#ifdef ENABLE_PI
+  if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0)
     {
+      puts ("pthread_mutexattr_setprotocol failed");
+      return 1;
+    }
+#endif
+
+  int e;
+  e = pthread_mutex_init (&m, &a);
+  if (e != 0)
+    {
+#ifdef ENABLE_PI
+      if (e == ENOTSUP)
+	{
+	  puts ("PI robust mutexes not supported");
+	  return 0;
+	}
+#endif
       puts ("mutex_init failed");
       return 1;
     }
@@ -123,7 +140,7 @@ do_test (void)
 	  return 1;
 	}
 
-      int e = pthread_barrier_wait (&b);
+      e = pthread_barrier_wait (&b);
       if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
 	{
 	  printf ("parent: barrier_wait failed in round %ld\n", n + 1);
@@ -164,7 +181,7 @@ do_test (void)
 	}
     }
 
-  int e = pthread_mutex_lock (&m);
+  e = pthread_mutex_lock (&m);
   if (e == 0)
     {
       puts ("parent: 2nd mutex_lock succeeded");
diff --git a/nptl/tst-robust8.c b/nptl/tst-robust8.c
index 19682e594f..9c636250d4 100644
--- a/nptl/tst-robust8.c
+++ b/nptl/tst-robust8.c
@@ -15,7 +15,7 @@ static void prepare (void);
 #define PREPARE(argc, argv) prepare ()
 static int do_test (void);
 #define TEST_FUNCTION do_test ()
-#define TIMEOUT 3
+#define TIMEOUT 5
 #include "../test-skeleton.c"
 
 
@@ -173,6 +173,13 @@ do_test (void)
       puts ("mutexattr_setpshared failed");
       return 1;
     }
+#ifdef ENABLE_PI
+  if (pthread_mutexattr_setprotocol (&ma, PTHREAD_PRIO_INHERIT) != 0)
+    {
+      puts ("pthread_mutexattr_setprotocol failed");
+      return 1;
+    }
+#endif
 
   for (int round = 1; round <= ROUNDS; ++round)
     {
@@ -181,7 +188,11 @@ do_test (void)
 	  int e = pthread_mutex_init (&map[n], &ma);
 	  if (e == ENOTSUP)
 	    {
+#ifdef ENABLE_PI
+	      puts ("cannot support pshared robust PI mutexes");
+#else
 	      puts ("cannot support pshared robust mutexes");
+#endif
 	      return 0;
 	    }
 	  if (e != 0)
diff --git a/nptl/tst-robustpi1.c b/nptl/tst-robustpi1.c
new file mode 100644
index 0000000000..031291b296
--- /dev/null
+++ b/nptl/tst-robustpi1.c
@@ -0,0 +1,2 @@
+#define ENABLE_PI 1
+#include "tst-robust1.c"
diff --git a/nptl/tst-robustpi2.c b/nptl/tst-robustpi2.c
new file mode 100644
index 0000000000..ac411c7736
--- /dev/null
+++ b/nptl/tst-robustpi2.c
@@ -0,0 +1,2 @@
+#define ENABLE_PI 1
+#include "tst-robust2.c"
diff --git a/nptl/tst-robustpi3.c b/nptl/tst-robustpi3.c
new file mode 100644
index 0000000000..7dcf691e82
--- /dev/null
+++ b/nptl/tst-robustpi3.c
@@ -0,0 +1,2 @@
+#define ENABLE_PI 1
+#include "tst-robust3.c"
diff --git a/nptl/tst-robustpi4.c b/nptl/tst-robustpi4.c
new file mode 100644
index 0000000000..6c7b0aa7be
--- /dev/null
+++ b/nptl/tst-robustpi4.c
@@ -0,0 +1,2 @@
+#define ENABLE_PI 1
+#include "tst-robust4.c"
diff --git a/nptl/tst-robustpi5.c b/nptl/tst-robustpi5.c
new file mode 100644
index 0000000000..a494c332f1
--- /dev/null
+++ b/nptl/tst-robustpi5.c
@@ -0,0 +1,2 @@
+#define ENABLE_PI 1
+#include "tst-robust5.c"
diff --git a/nptl/tst-robustpi6.c b/nptl/tst-robustpi6.c
new file mode 100644
index 0000000000..3b1482fc22
--- /dev/null
+++ b/nptl/tst-robustpi6.c
@@ -0,0 +1,2 @@
+#define ENABLE_PI 1
+#include "tst-robust6.c"
diff --git a/nptl/tst-robustpi7.c b/nptl/tst-robustpi7.c
new file mode 100644
index 0000000000..f8892f3521
--- /dev/null
+++ b/nptl/tst-robustpi7.c
@@ -0,0 +1,2 @@
+#define ENABLE_PI 1
+#include "tst-robust7.c"
diff --git a/nptl/tst-robustpi8.c b/nptl/tst-robustpi8.c
new file mode 100644
index 0000000000..cbea3d6d77
--- /dev/null
+++ b/nptl/tst-robustpi8.c
@@ -0,0 +1,2 @@
+#define ENABLE_PI 1
+#include "tst-robust8.c"
diff --git a/stdlib/cxa_atexit.c b/stdlib/cxa_atexit.c
index 9b7a932b85..3bdf871e53 100644
--- a/stdlib/cxa_atexit.c
+++ b/stdlib/cxa_atexit.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999, 2001, 2002, 2005 Free Software Foundation, Inc.
+/* Copyright (C) 1999, 2001, 2002, 2005, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -56,6 +56,7 @@ __libc_lock_define_initialized (static, lock)
 
 static struct exit_function_list initial;
 struct exit_function_list *__exit_funcs = &initial;
+uint64_t __new_exitfn_called;
 
 struct exit_function *
 __new_exitfn (void)
@@ -111,7 +112,10 @@ __new_exitfn (void)
 
   /* Mark entry as used, but we don't know the flavor now.  */
   if (r != NULL)
-    r->flavor = ef_us;
+    {
+      r->flavor = ef_us;
+      ++__new_exitfn_called;
+    }
 
   __libc_lock_unlock (lock);
 
diff --git a/stdlib/cxa_finalize.c b/stdlib/cxa_finalize.c
index 43fcbc484f..bb49f36ddd 100644
--- a/stdlib/cxa_finalize.c
+++ b/stdlib/cxa_finalize.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999, 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
+/* Copyright (C) 1999,2001,2002,2003,2005,2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -31,22 +31,36 @@ __cxa_finalize (void *d)
 {
   struct exit_function_list *funcs;
 
+ restart:
   for (funcs = __exit_funcs; funcs; funcs = funcs->next)
     {
       struct exit_function *f;
 
       for (f = &funcs->fns[funcs->idx - 1]; f >= &funcs->fns[0]; --f)
-	if ((d == NULL || d == f->func.cxa.dso_handle)
-	    /* We don't want to run this cleanup more than once.  */
-	    && ! atomic_compare_and_exchange_bool_acq (&f->flavor, ef_free,
-						       ef_cxa))
-	  {
-	    void (*cxafn) (void *arg, int status) = f->func.cxa.fn;
+	{
+	  void (*cxafn) (void *arg, int status);
+	  void *cxaarg;
+
+	  if ((d == NULL || d == f->func.cxa.dso_handle)
+	      /* We don't want to run this cleanup more than once.  */
+	      && (cxafn = f->func.cxa.fn,
+		  cxaarg = f->func.cxa.arg,
+		  ! atomic_compare_and_exchange_bool_acq (&f->flavor, ef_free,
+							  ef_cxa)))
+	    {
+	      uint64_t check = __new_exitfn_called;
+
 #ifdef PTR_DEMANGLE
-	    PTR_DEMANGLE (cxafn);
+	      PTR_DEMANGLE (cxafn);
 #endif
-	    cxafn (f->func.cxa.arg, 0);
-	  }
+	      cxafn (cxaarg, 0);
+
+	      /* It is possible that that last exit function registered
+		 more exit functions.  Start the loop over.  */
+	      if (__builtin_expect (check != __new_exitfn_called, 0))
+		goto restart;
+	    }
+	}
     }
 
   /* Remove the registered fork handlers.  We do not have to
diff --git a/stdlib/exit.h b/stdlib/exit.h
index 055506f04e..779675d134 100644
--- a/stdlib/exit.h
+++ b/stdlib/exit.h
@@ -1,4 +1,5 @@
-/* Copyright (C) 1991,1996,1997,1999,2001,2002 Free Software Foundation, Inc.
+/* Copyright (C) 1991,1996,1997,1999,2001,2002,2006
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -19,6 +20,7 @@
 #ifndef	_EXIT_H
 #define _EXIT_H 1
 
+#include <stdint.h>
 
 enum
 {
@@ -59,5 +61,6 @@ struct exit_function_list
 extern struct exit_function_list *__exit_funcs attribute_hidden;
 
 extern struct exit_function *__new_exitfn (void);
+extern uint64_t __new_exitfn_called attribute_hidden;
 
 #endif	/* exit.h  */
diff --git a/sysdeps/unix/sysv/linux/alpha/bits/fcntl.h b/sysdeps/unix/sysv/linux/alpha/bits/fcntl.h
index 9b2e635d60..6084c38c91 100644
--- a/sysdeps/unix/sysv/linux/alpha/bits/fcntl.h
+++ b/sysdeps/unix/sysv/linux/alpha/bits/fcntl.h
@@ -94,7 +94,7 @@
 # define F_NOTIFY	1026	/* Request notfications on a directory.	 */
 #endif
 
-/* for F_[GET|SET]FL */
+/* for F_[GET|SET]FD */
 #define FD_CLOEXEC	1	/* actually anything with low bit set goes */
 
 /* For posix fcntl() and `l_type' field of a `struct flock' for lockf() */
diff --git a/sysdeps/unix/sysv/linux/i386/bits/fcntl.h b/sysdeps/unix/sysv/linux/i386/bits/fcntl.h
index 81d9932675..1f7ac0f25a 100644
--- a/sysdeps/unix/sysv/linux/i386/bits/fcntl.h
+++ b/sysdeps/unix/sysv/linux/i386/bits/fcntl.h
@@ -99,7 +99,7 @@
 # define F_NOTIFY	1026	/* Request notfications on a directory.	 */
 #endif
 
-/* For F_[GET|SET]FL.  */
+/* For F_[GET|SET]FD.  */
 #define FD_CLOEXEC	1	/* actually anything with low bit set goes */
 
 /* For posix fcntl() and `l_type' field of a `struct flock' for lockf().  */
diff --git a/sysdeps/unix/sysv/linux/ia64/bits/fcntl.h b/sysdeps/unix/sysv/linux/ia64/bits/fcntl.h
index 4695d92618..1ddb4e349f 100644
--- a/sysdeps/unix/sysv/linux/ia64/bits/fcntl.h
+++ b/sysdeps/unix/sysv/linux/ia64/bits/fcntl.h
@@ -95,7 +95,7 @@
 # define F_NOTIFY	1026	/* Request notfications on a directory.	 */
 #endif
 
-/* For F_[GET|SET]FL.  */
+/* For F_[GET|SET]FD.  */
 #define FD_CLOEXEC	1	/* actually anything with low bit set goes */
 
 /* For posix fcntl() and `l_type' field of a `struct flock' for lockf().  */
diff --git a/sysdeps/unix/sysv/linux/kernel-features.h b/sysdeps/unix/sysv/linux/kernel-features.h
index 139e3d5a72..e54f675dbe 100644
--- a/sysdeps/unix/sysv/linux/kernel-features.h
+++ b/sysdeps/unix/sysv/linux/kernel-features.h
@@ -431,29 +431,30 @@
 /* pselect was introduced just after 2.6.16-rc1.  Due to the way the
    kernel versions are advertised we can only rely on 2.6.17 to have
    the code.  */
-#if __LINUX_KERNEL_VERSION >= 0x020611 \
-    && (defined __i386__ || defined __powerpc__)
+#if __LINUX_KERNEL_VERSION >= 0x020611 && !defined __x86_64__
 # define __ASSUME_PSELECT	1
 #endif
 
 /* ppoll was introduced just after 2.6.16-rc1.  Due to the way the
    kernel versions are advertised we can only rely on 2.6.17 to have
    the code.  */
-#if __LINUX_KERNEL_VERSION >= 0x020611 \
-    && (defined __i386__ || defined __powerpc__)
+#if __LINUX_KERNEL_VERSION >= 0x020611 && !defined __x86_64__
 # define __ASSUME_PPOLL	1
 #endif
 
 /* The *at syscalls were introduced just after 2.6.16-rc1.  Due to the way the
    kernel versions are advertised we can only rely on 2.6.17 to have
    the code.  */
-#if __LINUX_KERNEL_VERSION >= 0x020611 \
-    && (defined __i386__ || defined __x86_64__)
+#if __LINUX_KERNEL_VERSION >= 0x020611
 # define __ASSUME_ATFCTS	1
 #endif
 
 /* Support for inter-process robust mutexes was added in 2.6.17.  */
-#if __LINUX_KERNEL_VERSION >= 0x020611 \
-    && (defined __i386__ || defined __x86_64__)
+#if __LINUX_KERNEL_VERSION >= 0x020611
 # define __ASSUME_SET_ROBUST_LIST	1
 #endif
+
+/* Support for PI futexes was added in 2.6.18.  */
+#if __LINUX_KERNEL_VERSION >= 0x020612
+# define __ASSUME_FUTEX_LOCK_PI	1
+#endif
diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h b/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h
index 5d6bb6fe44..57fc7bd987 100644
--- a/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h
+++ b/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h
@@ -99,7 +99,7 @@
 # define F_NOTIFY	1026	/* Request notfications on a directory.	 */
 #endif
 
-/* For F_[GET|SET]FL.  */
+/* For F_[GET|SET]FD.  */
 #define FD_CLOEXEC	1	/* actually anything with low bit set goes */
 
 /* For posix fcntl() and `l_type' field of a `struct flock' for lockf().  */
diff --git a/sysdeps/unix/sysv/linux/s390/bits/fcntl.h b/sysdeps/unix/sysv/linux/s390/bits/fcntl.h
index 166bae59bf..e5a917dbfa 100644
--- a/sysdeps/unix/sysv/linux/s390/bits/fcntl.h
+++ b/sysdeps/unix/sysv/linux/s390/bits/fcntl.h
@@ -114,7 +114,7 @@
 # define F_NOTIFY	1026	/* Request notfications on a directory.	 */
 #endif
 
-/* For F_[GET|SET]FL.  */
+/* For F_[GET|SET]FD.  */
 #define FD_CLOEXEC	1	/* actually anything with low bit set goes */
 
 /* For posix fcntl() and `l_type' field of a `struct flock' for lockf().  */
diff --git a/sysdeps/unix/sysv/linux/sh/bits/fcntl.h b/sysdeps/unix/sysv/linux/sh/bits/fcntl.h
index 81d9932675..1f7ac0f25a 100644
--- a/sysdeps/unix/sysv/linux/sh/bits/fcntl.h
+++ b/sysdeps/unix/sysv/linux/sh/bits/fcntl.h
@@ -99,7 +99,7 @@
 # define F_NOTIFY	1026	/* Request notfications on a directory.	 */
 #endif
 
-/* For F_[GET|SET]FL.  */
+/* For F_[GET|SET]FD.  */
 #define FD_CLOEXEC	1	/* actually anything with low bit set goes */
 
 /* For posix fcntl() and `l_type' field of a `struct flock' for lockf().  */
diff --git a/sysdeps/unix/sysv/linux/sparc/bits/fcntl.h b/sysdeps/unix/sysv/linux/sparc/bits/fcntl.h
index 022f24ac17..a965d31654 100644
--- a/sysdeps/unix/sysv/linux/sparc/bits/fcntl.h
+++ b/sysdeps/unix/sysv/linux/sparc/bits/fcntl.h
@@ -116,7 +116,7 @@
 # define F_SETLKW64	14	/* Set record locking info (blocking).  */
 #endif
 
-/* for F_[GET|SET]FL */
+/* for F_[GET|SET]FD */
 #define FD_CLOEXEC	1	/* actually anything with low bit set goes */
 
 /* For posix fcntl() and `l_type' field of a `struct flock' for lockf().  */
diff --git a/sysdeps/unix/sysv/linux/x86_64/bits/fcntl.h b/sysdeps/unix/sysv/linux/x86_64/bits/fcntl.h
index 771de60711..4f10f22224 100644
--- a/sysdeps/unix/sysv/linux/x86_64/bits/fcntl.h
+++ b/sysdeps/unix/sysv/linux/x86_64/bits/fcntl.h
@@ -113,7 +113,7 @@
 # define F_NOTIFY	1026	/* Request notfications on a directory.	 */
 #endif
 
-/* For F_[GET|SET]FL.  */
+/* For F_[GET|SET]FD.  */
 #define FD_CLOEXEC	1	/* actually anything with low bit set goes */
 
 /* For posix fcntl() and `l_type' field of a `struct flock' for lockf().  */