summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2006-02-17 16:15:56 +0000
committerJakub Jelinek <jakub@redhat.com>2006-02-17 16:15:56 +0000
commit9c09cd93597a91d6b0b59c8813be97d530e7551c (patch)
treecd7ea8e6dc157e92ffd5f20dfa997e8be5b7da8b
parent7d8db4cd587349f485fb85f4bea9e3011a3e55d7 (diff)
Updated to fedora-glibc-20060217T1609
-rw-r--r--ChangeLog21
-rw-r--r--fedora/branch.mk4
-rw-r--r--fedora/glibc.spec.in6
-rw-r--r--nptl/ChangeLog42
-rw-r--r--nptl/Makefile2
-rw-r--r--nptl/descr.h2
-rw-r--r--nptl/pthreadP.h12
-rw-r--r--nptl/pthread_create.c7
-rw-r--r--nptl/pthread_mutex_consistent.c6
-rw-r--r--nptl/pthread_mutex_destroy.c12
-rw-r--r--nptl/pthread_mutex_lock.c113
-rw-r--r--nptl/pthread_mutex_timedlock.c113
-rw-r--r--nptl/pthread_mutex_trylock.c130
-rw-r--r--nptl/pthread_mutex_unlock.c41
-rw-r--r--nptl/sysdeps/unix/sysv/linux/Makefile5
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelrobustlock.S186
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelrobustlock.S20
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelrobustlock.S20
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h118
-rw-r--r--nptl/sysdeps/unix/sysv/linux/lowlevelrobustlock.sym6
-rw-r--r--nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c5
-rw-r--r--nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.h111
-rw-r--r--nptl/sysdeps/unix/sysv/linux/sh/lowlevelrobustlock.S224
-rw-r--r--nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h96
-rw-r--r--nptl/sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.S192
-rw-r--r--sysdeps/unix/sysv/linux/alpha/bits/mman.h2
-rw-r--r--sysdeps/unix/sysv/linux/i386/bits/mman.h2
-rw-r--r--sysdeps/unix/sysv/linux/ia64/bits/mman.h2
-rw-r--r--sysdeps/unix/sysv/linux/m68k/bits/mman.h2
-rw-r--r--sysdeps/unix/sysv/linux/not-cancel.h22
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/bits/mman.h2
-rw-r--r--sysdeps/unix/sysv/linux/s390/bits/mman.h2
-rw-r--r--sysdeps/unix/sysv/linux/sh/bits/mman.h2
-rw-r--r--sysdeps/unix/sysv/linux/sparc/bits/mman.h2
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/bits/mman.h2
35 files changed, 1337 insertions, 197 deletions
diff --git a/ChangeLog b/ChangeLog
index c9e0b0cee3..582f248704 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2006-02-15 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/unix/sysv/linux/sparc/bits/mman.h: Define MADV_DONTFORK
+ and MADV_DOFORK.
+ * sysdeps/unix/sysv/linux/ia64/bits/mman.h: Likewise.
+ * sysdeps/unix/sysv/linux/sh/bits/mman.h: Likewise.
+ * sysdeps/unix/sysv/linux/i386/bits/mman.h: Likewise.
+ * sysdeps/unix/sysv/linux/s390/bits/mman.h: Likewise.
+ * sysdeps/unix/sysv/linux/x86_64/bits/mman.h: Likewise.
+ * sysdeps/unix/sysv/linux/alpha/bits/mman.h: Likewise.
+ * sysdeps/unix/sysv/linux/m68k/bits/mman.h: Likewise.
+ * sysdeps/unix/sysv/linux/powerpc/bits/mman.h: Likewise.
+
+2006-02-13 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/unix/sysv/linux/not-cancel.h (__openat_not_cancel,
+ __openat64_not_cancel): Remove prototypes.
+ (__openat_nocancel, __openat64_nocancel): New prototypes or defines.
+ (openat_not_cancel, openat_not_cancel_3, openat64_not_cancel,
+ openat64_not_cancel_3): Use them.
+
2006-02-12 Ulrich Drepper <drepper@redhat.com>
* io/ftw.c: Start using *at functions.
diff --git a/fedora/branch.mk b/fedora/branch.mk
index e9760460ca..2768f05c5e 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-02-13 06:50 UTC
-fedora-sync-tag := fedora-glibc-20060213T0650
+fedora-sync-date := 2006-02-17 16:09 UTC
+fedora-sync-tag := fedora-glibc-20060217T1609
diff --git a/fedora/glibc.spec.in b/fedora/glibc.spec.in
index 5547e9a22a..06cd9181c6 100644
--- a/fedora/glibc.spec.in
+++ b/fedora/glibc.spec.in
@@ -1,4 +1,4 @@
-%define glibcrelease 37
+%define glibcrelease 38
%define auxarches i586 i686 athlon sparcv9 alphaev6
%define prelinkarches noarch
%define xenarches i686 athlon
@@ -1332,6 +1332,10 @@ rm -f *.filelist*
%endif
%changelog
+* Fri Feb 17 2006 Jakub Jelinek <jakub@redhat.com> 2.3.90-38
+- update from CVS
+ - robust mutexes rewrite
+
* Mon Feb 13 2006 Jakub Jelinek <jakub@redhat.com> 2.3.90-37
- update from CVS
- *at fixes
diff --git a/nptl/ChangeLog b/nptl/ChangeLog
index 73bcfaa84f..454295fb11 100644
--- a/nptl/ChangeLog
+++ b/nptl/ChangeLog
@@ -1,5 +1,20 @@
+2006-02-17 Kaz Kojima <kkojima@rr.iij4u.or.jp>
+
+ * sysdeps/unix/sysv/linux/sh/lowlevellock.h: Add lll_robust_mutex_*
+ definitions.
+ * sysdeps/unix/sysv/linux/sh/lowlevelrobustlock.S: New file.
+
+2006-02-17 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h
+ (lll_robust_mutex_unlock): Avoid unnecessary wakeups.
+ * sysdeps/unix/sysv/linux/i386/lowlevellock.h
+ (lll_robust_mutex_unlock): Likewise.
+
2006-02-13 Jakub Jelinek <jakub@redhat.com>
+ * descr.h [!__PTHREAD_MUTEX_HAVE_PREV] (DEQUEUE_MUTEX):
+ Set robust_list.__next rather than robust_list.
* sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h
(__pthread_list_t): New typedef.
(pthread_mutex_t): Replace __next and __prev fields with __list.
@@ -19,6 +34,33 @@
(__pthread_slist_t): New typedef.
(pthread_mutex_t): Replace __next field with __list.
+2006-02-15 Ulrich Drepper <drepper@redhat.com>
+
+ * pthreadp.h: Define PTHREAD_MUTEX_INCONSISTENT instead of
+ PTHREAD_MUTEX_OWNERDEAD.
+ (PTHREAD_MUTEX_ROBUST_PRIVATE_NP): Define as 16, not 256.
+ Define FUTEX_WAITERS, FUTEX_OWNER_DIED, FUTEX_TID_MASK.
+ * Makefile (libpthread-routines): Add lowlevelrobustlock.
+ * pthread_create.c (start_thread): Very much simplify robust_list loop.
+ * pthread_mutex_consistent.c: Inconsistent mutex have __owner now set
+ to PTHREAD_MUTEX_INCONSISTENT.
+ * pthread_mutex_destroy.c: Allow destroying of inconsistent mutexes.
+ * pthread_mutex_lock.c: Reimplement robust mutex handling.
+ * pthread_mutex_trylock.c: Likewise.
+ * pthread_mutex_timedlock.c: Likewise.
+ * pthread_mutex_unlock.c: Likewise.
+ * sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c: Likewise.
+ * sysdeps/unix/sysv/linux/Makefile (gen-as-const-headers): Add
+ lowlevelrobustlock.sym.
+ * sysdeps/unix/sysv/linux/lowlevelrobustlock.sym: New file.
+ * sysdeps/unix/sysv/linux/i386/lowlevellock.h: Add lll_robust_mutex_*
+ definitions.
+ * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Likewise.
+ * sysdeps/unix/sysv/linux/i386/i486/lowlevelrobustlock.S: New file.
+ * sysdeps/unix/sysv/linux/i386/i586/lowlevelrobustlock.S: New file.
+ * sysdeps/unix/sysv/linux/i386/i686/lowlevelrobustlock.S: New file.
+ * sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.S: New file.
+
2006-02-12 Ulrich Drepper <drepper@redhat.com>
* allocatestack.c (allocate_stack): Initialize robust_list.
diff --git a/nptl/Makefile b/nptl/Makefile
index 2b245dfb31..60203cd114 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -100,7 +100,7 @@ libpthread-routines = init vars events version \
cleanup_defer_compat unwind \
pt-longjmp pt-cleanup\
cancellation \
- lowlevellock \
+ lowlevellock lowlevelrobustlock \
pt-vfork \
ptw-write ptw-read ptw-close ptw-fcntl ptw-accept \
ptw-connect ptw-recv ptw-recvfrom ptw-recvmsg ptw-send \
diff --git a/nptl/descr.h b/nptl/descr.h
index 6984138537..d5491c1355 100644
--- a/nptl/descr.h
+++ b/nptl/descr.h
@@ -166,7 +166,7 @@ struct pthread
do { \
__pthread_slist_t *runp = THREAD_GETMEM (THREAD_SELF, robust_list.__next);\
if (runp == &mutex->__data.__list) \
- THREAD_SETMEM (THREAD_SELF, robust_list, runp->__next); \
+ THREAD_SETMEM (THREAD_SELF, robust_list.__next, runp->__next); \
else \
{ \
while (runp->__next != &mutex->__data.__list) \
diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
index 61b7176159..77d8f5ad24 100644
--- a/nptl/pthreadP.h
+++ b/nptl/pthreadP.h
@@ -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.
@@ -52,7 +52,7 @@
/* Magic cookie representing robust mutex with dead owner. */
-#define PTHREAD_MUTEX_OWNERDEAD INT_MAX
+#define PTHREAD_MUTEX_INCONSISTENT INT_MAX
/* Magic cookie representing not recoverable robust mutex. */
#define PTHREAD_MUTEX_NOTRECOVERABLE (INT_MAX - 1)
@@ -60,7 +60,7 @@
/* Internal mutex type value. */
enum
{
- PTHREAD_MUTEX_ROBUST_PRIVATE_NP = 256,
+ PTHREAD_MUTEX_ROBUST_PRIVATE_NP = 16,
PTHREAD_MUTEX_ROBUST_PRIVATE_RECURSIVE_NP
= PTHREAD_MUTEX_ROBUST_PRIVATE_NP | PTHREAD_MUTEX_RECURSIVE_NP,
PTHREAD_MUTEX_ROBUST_PRIVATE_ERRORCHECK_NP
@@ -77,6 +77,12 @@ enum
(PTHREAD_MUTEXATTR_FLAG_ROBUST | PTHREAD_MUTEXATTR_FLAG_PSHARED)
+/* Bits used in robust mutex implementation. */
+#define FUTEX_WAITERS 0x80000000
+#define FUTEX_OWNER_DIED 0x40000000
+#define FUTEX_TID_MASK 0x1fffffff
+
+
/* Internal variables. */
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
index b1253b2243..f3d90ecebf 100644
--- a/nptl/pthread_create.c
+++ b/nptl/pthread_create.c
@@ -324,17 +324,12 @@ start_thread (void *arg)
((char *) robust - offsetof (struct __pthread_mutex_s, __list));
robust = robust->__next;
- assert (lll_mutex_islocked (this->__lock));
- this->__count = 0;
- --this->__nusers;
- assert (this->__owner != PTHREAD_MUTEX_NOTRECOVERABLE);
- this->__owner = PTHREAD_MUTEX_OWNERDEAD;
this->__list.__next = NULL;
#ifdef __PTHREAD_MUTEX_HAVE_PREV
this->__list.__prev = NULL;
#endif
- lll_mutex_unlock (this->__lock);
+ lll_robust_mutex_dead (this->__lock);
}
while (robust != &pd->robust_list);
diff --git a/nptl/pthread_mutex_consistent.c b/nptl/pthread_mutex_consistent.c
index 2edfe8a5a6..0cfe972da0 100644
--- a/nptl/pthread_mutex_consistent.c
+++ b/nptl/pthread_mutex_consistent.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.
@@ -27,10 +27,10 @@ pthread_mutex_consistent_np (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))
+ || mutex->__data.__owner != PTHREAD_MUTEX_INCONSISTENT)
return EINVAL;
- mutex->__data.__owner = -mutex->__data.__owner;
+ mutex->__data.__owner = THREAD_GETMEM (THREAD_SELF, tid);
return 0;
}
diff --git a/nptl/pthread_mutex_destroy.c b/nptl/pthread_mutex_destroy.c
index 2bf76a9da3..19a647a846 100644
--- a/nptl/pthread_mutex_destroy.c
+++ b/nptl/pthread_mutex_destroy.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2005, 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
@@ -26,9 +26,17 @@ __pthread_mutex_destroy (mutex)
pthread_mutex_t *mutex;
{
if (mutex->__data.__nusers != 0)
- return EBUSY;
+ {
+ if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_PRIVATE_NP) != 0
+ && (mutex->__data.__lock & FUTEX_OWNER_DIED) != 0
+ && mutex->__data.__nusers == 1)
+ goto dead_robust_mutex;
+
+ return EBUSY;
+ }
/* Set to an invalid value. */
+ dead_robust_mutex:
mutex->__data.__kind = -1;
return 0;
diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c
index 420711a4d4..dd22567c71 100644
--- a/nptl/pthread_mutex_lock.c
+++ b/nptl/pthread_mutex_lock.c
@@ -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.
@@ -27,6 +27,7 @@
#ifndef LLL_MUTEX_LOCK
# define LLL_MUTEX_LOCK(mutex) lll_mutex_lock (mutex)
# define LLL_MUTEX_TRYLOCK(mutex) lll_mutex_trylock (mutex)
+# define LLL_ROBUST_MUTEX_LOCK(mutex, id) lll_robust_mutex_lock (mutex, id)
#endif
@@ -36,6 +37,7 @@ __pthread_mutex_lock (mutex)
{
assert (sizeof (mutex->__size) >= sizeof (mutex->__data));
+ int oldval;
pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
int retval = 0;
@@ -107,60 +109,83 @@ __pthread_mutex_lock (mutex)
break;
case PTHREAD_MUTEX_ROBUST_PRIVATE_RECURSIVE_NP:
- /* Check whether we already hold the mutex. */
- if (abs (mutex->__data.__owner) == id)
+ case PTHREAD_MUTEX_ROBUST_PRIVATE_ERRORCHECK_NP:
+ case PTHREAD_MUTEX_ROBUST_PRIVATE_NP:
+ case PTHREAD_MUTEX_ROBUST_PRIVATE_ADAPTIVE_NP:
+ oldval = mutex->__data.__lock;
+ do
{
- /* 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);
+ if ((oldval & FUTEX_OWNER_DIED) != 0)
+ {
+ /* The previous owner died. Try locking the mutex. */
+ int newval;
+ while ((newval
+ = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+ id, oldval))
+ != oldval)
+ {
+ if ((newval & FUTEX_OWNER_DIED) == 0)
+ goto normal;
+ oldval = newval;
+ }
- mutex->__data.__count = 1;
+ /* We got the mutex. */
+ mutex->__data.__count = 1;
+ /* But it is inconsistent unless marked otherwise. */
+ mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
+
+ ENQUEUE_MUTEX (mutex);
+
+ /* 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
- goto robust;
+ return EOWNERDEAD;
+ }
- 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;
+ normal:
+ /* Check whether we already hold the mutex. */
+ if (__builtin_expect ((mutex->__data.__lock & FUTEX_TID_MASK)
+ == id, 0))
+ {
+ if (mutex->__data.__kind
+ == PTHREAD_MUTEX_ROBUST_PRIVATE_ERRORCHECK_NP)
+ return EDEADLK;
- /* FALLTHROUGH */
+ if (mutex->__data.__kind
+ == PTHREAD_MUTEX_ROBUST_PRIVATE_RECURSIVE_NP)
+ {
+ /* Just bump the counter. */
+ if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
+ /* Overflow of the counter. */
+ return EAGAIN;
- case PTHREAD_MUTEX_ROBUST_PRIVATE_NP:
- case PTHREAD_MUTEX_ROBUST_PRIVATE_ADAPTIVE_NP:
- LLL_MUTEX_LOCK (mutex->__data.__lock);
+ ++mutex->__data.__count;
- 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;
- }
+ return 0;
+ }
+ }
- /* This mutex is either healthy or we can try to recover it. */
- assert (mutex->__data.__owner == 0
- || mutex->__data.__owner == PTHREAD_MUTEX_OWNERDEAD);
+ oldval = LLL_ROBUST_MUTEX_LOCK (mutex->__data.__lock, id);
- 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;
+ 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;
+ }
}
+ while ((oldval & FUTEX_OWNER_DIED) != 0);
+ mutex->__data.__count = 1;
ENQUEUE_MUTEX (mutex);
break;
diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c
index bc4ead765d..b69caedc7c 100644
--- a/nptl/pthread_mutex_timedlock.c
+++ b/nptl/pthread_mutex_timedlock.c
@@ -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.
@@ -28,6 +28,7 @@ pthread_mutex_timedlock (mutex, abstime)
pthread_mutex_t *mutex;
const struct timespec *abstime;
{
+ int oldval;
pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
int result = 0;
@@ -103,67 +104,83 @@ 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)
+ case PTHREAD_MUTEX_ROBUST_PRIVATE_ERRORCHECK_NP:
+ case PTHREAD_MUTEX_ROBUST_PRIVATE_NP:
+ case PTHREAD_MUTEX_ROBUST_PRIVATE_ADAPTIVE_NP:
+ oldval = mutex->__data.__lock;
+ do
{
- /* Just bump the counter. */
- if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
- /* Overflow of the counter. */
- return EAGAIN;
-
- ++mutex->__data.__count;
+ if ((oldval & FUTEX_OWNER_DIED) != 0)
+ {
+ /* The previous owner died. Try locking the mutex. */
+ int newval;
+ while ((newval
+ = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+ id, oldval))
+ != oldval)
+ {
+ if ((newval & FUTEX_OWNER_DIED) == 0)
+ goto normal;
+ oldval = newval;
+ }
- goto out;
- }
+ /* We got the mutex. */
+ mutex->__data.__count = 1;
+ /* But it is inconsistent unless marked otherwise. */
+ mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
- /* We have to get the mutex. */
- result = lll_mutex_timedlock (mutex->__data.__lock, abstime);
+ ENQUEUE_MUTEX (mutex);
- if (result != 0)
- goto out;
+ /* Note that we deliberately exist 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;
+ }
- /* Only locked once so far. */
- mutex->__data.__count = 1;
- goto robust;
+ normal:
+ /* Check whether we already hold the mutex. */
+ if (__builtin_expect ((mutex->__data.__lock & FUTEX_TID_MASK)
+ == id, 0))
+ {
+ if (mutex->__data.__kind
+ == PTHREAD_MUTEX_ROBUST_PRIVATE_ERRORCHECK_NP)
+ return EDEADLK;
- 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;
+ if (mutex->__data.__kind
+ == PTHREAD_MUTEX_ROBUST_PRIVATE_RECURSIVE_NP)
+ {
+ /* Just bump the counter. */
+ if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
+ /* Overflow of the counter. */
+ return EAGAIN;
- /* FALLTHROUGH */
+ ++mutex->__data.__count;
- case PTHREAD_MUTEX_ROBUST_PRIVATE_NP:
- case PTHREAD_MUTEX_ROBUST_PRIVATE_ADAPTIVE_NP:
- result = lll_mutex_timedlock (mutex->__data.__lock, abstime);
+ return 0;
+ }
+ }
- if (result != 0)
- goto out;
+ result = lll_robust_mutex_timedlock (mutex->__data.__lock, abstime,
+ id);
- 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;
- }
+ 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 (result == ETIMEDOUT || result == EINVAL)
+ goto out;
- 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;
+ oldval = result;
}
+ while ((oldval & FUTEX_OWNER_DIED) != 0);
+ mutex->__data.__count = 1;
ENQUEUE_MUTEX (mutex);
break;
diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c
index ae73ecc39b..5a13ea6925 100644
--- a/nptl/pthread_mutex_trylock.c
+++ b/nptl/pthread_mutex_trylock.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2005, 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
@@ -28,6 +28,7 @@ int
__pthread_mutex_trylock (mutex)
pthread_mutex_t *mutex;
{
+ int oldval;
pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP))
@@ -77,73 +78,88 @@ __pthread_mutex_trylock (mutex)
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. */
- 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))
+ oldval = mutex->__data.__lock;
+ do
{
- retval = EOWNERDEAD;
- /* We signal ownership of a not yet recovered robust
- mutex by storing the negative thread ID. */
- id = -id;
+ if ((oldval & FUTEX_OWNER_DIED) != 0)
+ {
+ /* The previous owner died. Try locking the mutex. */
+ int newval;
+ while ((newval
+ = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+ id, oldval))
+ != oldval)
+ {
+ if ((newval & FUTEX_OWNER_DIED) == 0)
+ goto normal;
+ oldval = newval;
+ }
+
+ /* We got the mutex. */
+ mutex->__data.__count = 1;
+ /* But it is inconsistent unless marked otherwise. */
+ mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
+
+ ENQUEUE_MUTEX (mutex);
+
+ /* Note that we deliberately exist 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;
+ }
+
+ normal:
+ /* Check whether we already hold the mutex. */
+ if (__builtin_expect ((mutex->__data.__lock & FUTEX_TID_MASK)
+ == id, 0))
+ {
+ if (mutex->__data.__kind
+ == PTHREAD_MUTEX_ROBUST_PRIVATE_ERRORCHECK_NP)
+ return EDEADLK;
+
+ if (mutex->__data.__kind
+ == PTHREAD_MUTEX_ROBUST_PRIVATE_RECURSIVE_NP)
+ {
+ /* 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 = lll_robust_mutex_trylock (mutex->__data.__lock, id);
+ if (oldval != 0 && (oldval & FUTEX_OWNER_DIED) == 0)
+ return EBUSY;
+
+ robust:
+ if (__builtin_expect (mutex->__data.__owner
+ == PTHREAD_MUTEX_NOTRECOVERABLE, 0))
+ {
+ /* This mutex is now not recoverable. */
+ mutex->__data.__count = 0;
+ if (oldval == id)
+ lll_mutex_unlock (mutex->__data.__lock);
+ return ENOTRECOVERABLE;
+ }
}
+ while ((oldval & FUTEX_OWNER_DIED) != 0);
ENQUEUE_MUTEX (mutex);
mutex->__data.__owner = id;
++mutex->__data.__nusers;
+ mutex->__data.__count = 1;
+
+ return 0;
- 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 4d87381065..d41eefe34c 100644
--- a/nptl/pthread_mutex_unlock.c
+++ b/nptl/pthread_mutex_unlock.c
@@ -41,23 +41,32 @@ __pthread_mutex_unlock_usercnt (mutex, decr)
if (--mutex->__data.__count != 0)
/* We still hold the mutex. */
return 0;
- break;
+ goto normal;
case PTHREAD_MUTEX_ERRORCHECK_NP:
/* Error checking mutex. */
if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)
|| ! lll_mutex_islocked (mutex->__data.__lock))
return EPERM;
- break;
+ /* FALLTHROUGH */
case PTHREAD_MUTEX_TIMED_NP:
case PTHREAD_MUTEX_ADAPTIVE_NP:
- /* Normal mutex. Nothing special to do. */
+ /* Always reset the owner field. */
+ normal:
+ mutex->__data.__owner = 0;
+ if (decr)
+ /* One less user. */
+ --mutex->__data.__nusers;
+
+ /* Unlock. */
+ lll_mutex_unlock (mutex->__data.__lock);
break;
case PTHREAD_MUTEX_ROBUST_PRIVATE_RECURSIVE_NP:
/* Recursive mutex. */
- if (mutex->__data.__owner == -THREAD_GETMEM (THREAD_SELF, tid))
+ if ((mutex->__data.__lock & FUTEX_TID_MASK)
+ == THREAD_GETMEM (THREAD_SELF, tid))
{
if (--mutex->__data.__count != 0)
/* We still hold the mutex. */
@@ -78,7 +87,8 @@ __pthread_mutex_unlock_usercnt (mutex, decr)
case PTHREAD_MUTEX_ROBUST_PRIVATE_ERRORCHECK_NP:
case PTHREAD_MUTEX_ROBUST_PRIVATE_NP:
case PTHREAD_MUTEX_ROBUST_PRIVATE_ADAPTIVE_NP:
- if (abs (mutex->__data.__owner) != THREAD_GETMEM (THREAD_SELF, tid)
+ if ((mutex->__data.__lock & FUTEX_TID_MASK)
+ != THREAD_GETMEM (THREAD_SELF, tid)
|| ! lll_mutex_islocked (mutex->__data.__lock))
return EPERM;
@@ -86,15 +96,21 @@ __pthread_mutex_unlock_usercnt (mutex, decr)
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))
+ == PTHREAD_MUTEX_INCONSISTENT, 0))
notrecoverable:
newowner = PTHREAD_MUTEX_NOTRECOVERABLE;
robust:
/* Remove mutex from the list. */
DEQUEUE_MUTEX (mutex);
+
+ mutex->__data.__owner = newowner;
+ if (decr)
+ /* One less user. */
+ --mutex->__data.__nusers;
+
+ /* Unlock. */
+ lll_robust_mutex_unlock (mutex->__data.__lock);
break;
default:
@@ -102,15 +118,6 @@ __pthread_mutex_unlock_usercnt (mutex, decr)
return EINVAL;
}
- /* Always reset the owner field. */
- mutex->__data.__owner = newowner;
- if (decr)
- /* One less user. */
- --mutex->__data.__nusers;
-
- /* Unlock. */
- lll_mutex_unlock (mutex->__data.__lock);
-
return 0;
}
diff --git a/nptl/sysdeps/unix/sysv/linux/Makefile b/nptl/sysdeps/unix/sysv/linux/Makefile
index 14f513c127..88dce1a886 100644
--- a/nptl/sysdeps/unix/sysv/linux/Makefile
+++ b/nptl/sysdeps/unix/sysv/linux/Makefile
@@ -1,4 +1,4 @@
-# Copyright (C) 2002, 2003, 2004, 2005 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.
@@ -24,7 +24,8 @@ sysdep_routines += register-atfork unregister-atfork libc_pthread_init \
libpthread-sysdep_routines += pt-fork pthread_mutex_cond_lock
gen-as-const-headers += lowlevelcond.sym lowlevelrwlock.sym \
- lowlevelbarrier.sym unwindbuf.sym
+ lowlevelbarrier.sym unwindbuf.sym \
+ lowlevelrobustlock.sym
endif
ifeq ($(subdir),posix)
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelrobustlock.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelrobustlock.S
new file mode 100644
index 0000000000..1c516c7424
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelrobustlock.S
@@ -0,0 +1,186 @@
+/* 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.
+
+ 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 <sysdep.h>
+#include <pthread-errnos.h>
+#include <lowlevelrobustlock.h>
+
+ .text
+
+#ifndef LOCK
+# ifdef UP
+# define LOCK
+# else
+# define LOCK lock
+# endif
+#endif
+
+#define SYS_gettimeofday __NR_gettimeofday
+#define SYS_futex 240
+#define FUTEX_WAIT 0
+#define FUTEX_WAKE 1
+#define FUTEX_WAITERS 0x80000000
+#define FUTEX_OWNER_DIED 0x40000000
+
+
+ .globl __lll_robust_mutex_lock_wait
+ .type __lll_robust_mutex_lock_wait,@function
+ .hidden __lll_robust_mutex_lock_wait
+ .align 16
+__lll_robust_mutex_lock_wait:
+ pushl %edx
+ pushl %ebx
+ pushl %esi
+
+ movl %ecx, %ebx
+ xorl %esi, %esi /* No timeout. */
+ xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */
+
+4: movl %eax, %edx
+ orl $FUTEX_WAITERS, %edx
+
+ testl $FUTEX_OWNER_DIED, %eax
+ jnz 3f
+
+ cmpl %edx, %eax /* NB: %edx == 2 */
+ je 1f
+
+ LOCK
+ cmpxchgl %edx, (%ebx)
+ jnz 2f
+
+1: movl $SYS_futex, %eax
+ ENTER_KERNEL
+
+ movl (%ebx), %eax
+
+2: test %eax, %eax
+ jne 4b
+
+ movl %gs:TID, %edx
+ LOCK
+ cmpxchgl %edx, (%ebx)
+ jnz 4b
+ /* NB: %eax == 0 */
+
+3: popl %esi
+ popl %ebx
+ popl %edx
+ ret
+ .size __lll_robust_mutex_lock_wait,.-__lll_robust_mutex_lock_wait
+
+
+ .globl __lll_robust_mutex_timedlock_wait
+ .type __lll_robust_mutex_timedlock_wait,@function
+ .hidden __lll_robust_mutex_timedlock_wait
+ .align 16
+__lll_robust_mutex_timedlock_wait:
+ /* Check for a valid timeout value. */
+ cmpl $1000000000, 4(%edx)
+ jae 3f
+
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+ pushl %ebp
+
+ /* Stack frame for the timespec and timeval structs. */
+ subl $12, %esp
+
+ movl %ecx, %ebp
+ movl %edx, %edi
+
+1: movl %eax, 8(%esp)
+
+ /* Get current time. */
+ movl %esp, %ebx
+ xorl %ecx, %ecx
+ movl $SYS_gettimeofday, %eax
+ ENTER_KERNEL
+
+ /* Compute relative timeout. */
+ movl 4(%esp), %eax
+ movl $1000, %edx
+ mul %edx /* Milli seconds to nano seconds. */
+ movl (%edi), %ecx
+ movl 4(%edi), %edx
+ subl (%esp), %ecx
+ subl %eax, %edx
+ jns 4f
+ addl $1000000000, %edx
+ subl $1, %ecx
+4: testl %ecx, %ecx
+ js 8f /* Time is already up. */
+
+ /* Store relative timeout. */
+ movl %ecx, (%esp)
+ movl %edx, 4(%esp)
+
+ movl %ebp, %ebx
+
+ movl 8(%esp), %edx
+ movl %edx, %eax
+ orl $FUTEX_WAITERS, %edx
+
+ testl $FUTEX_OWNER_DIED, %eax
+ jnz 6f
+
+ cmpl %eax, %edx
+ je 2f
+
+ LOCK
+ cmpxchgl %edx, (%ebx)
+ movl $0, %ecx /* Must use mov to avoid changing cc. */
+ jnz 5f
+
+2:
+ /* Futex call. */
+ movl %esp, %esi
+ xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */
+ movl $SYS_futex, %eax
+ ENTER_KERNEL
+ movl %eax, %ecx
+
+ movl (%ebx), %eax
+
+5: testl %eax, %eax
+ jne 7f
+
+ movl %gs:TID, %edx
+ LOCK
+ cmpxchgl %edx, (%ebx)
+ jnz 7f
+
+6: addl $12, %esp
+ popl %ebp
+ popl %ebx
+ popl %esi
+ popl %edi
+ ret
+
+ /* Check whether the time expired. */
+7: cmpl $-ETIMEDOUT, %ecx
+ jne 1b
+
+8: movl $ETIMEDOUT, %eax
+ jmp 6b
+
+3: movl $EINVAL, %eax
+ ret
+ .size __lll_robust_mutex_timedlock_wait,.-__lll_robust_mutex_timedlock_wait
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelrobustlock.S b/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelrobustlock.S
new file mode 100644
index 0000000000..f768e16a7d
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelrobustlock.S
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include "../i486/lowlevelrobustlock.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelrobustlock.S b/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelrobustlock.S
new file mode 100644
index 0000000000..f768e16a7d
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelrobustlock.S
@@ -0,0 +1,20 @@
+/* Copyright (C) 2002, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include "../i486/lowlevelrobustlock.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h b/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h
index b233d9747f..afdba009a0 100644
--- a/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h
+++ b/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h
@@ -139,6 +139,16 @@ extern int __lll_mutex_unlock_wake (int *__futex)
ret; })
+#define lll_robust_mutex_trylock(futex, id) \
+ ({ int ret; \
+ __asm __volatile (LOCK_INSTR "cmpxchgl %2, %1" \
+ : "=a" (ret), "=m" (futex) \
+ : "r" (id), "m" (futex), \
+ "0" (LLL_MUTEX_LOCK_INITIALIZER) \
+ : "memory"); \
+ ret; })
+
+
#define lll_mutex_cond_trylock(futex) \
({ int ret; \
__asm __volatile (LOCK_INSTR "cmpxchgl %2, %1" \
@@ -167,6 +177,25 @@ extern int __lll_mutex_unlock_wake (int *__futex)
: "memory"); })
+#define lll_robust_mutex_lock(futex, id) \
+ ({ int result, ignore; \
+ __asm __volatile (LOCK_INSTR "cmpxchgl %1, %2\n\t" \
+ "jnz _L_mutex_lock_%=\n\t" \
+ ".subsection 1\n\t" \
+ ".type _L_mutex_lock_%=,@function\n" \
+ "_L_mutex_lock_%=:\n\t" \
+ "leal %2, %%ecx\n\t" \
+ "call __lll_robust_mutex_lock_wait\n\t" \
+ "jmp 1f\n\t" \
+ ".size _L_mutex_lock_%=,.-_L_mutex_lock_%=\n" \
+ ".previous\n" \
+ "1:" \
+ : "=a" (result), "=c" (ignore), "=m" (futex) \
+ : "0" (0), "1" (id), "m" (futex) \
+ : "memory"); \
+ result; })
+
+
/* Special version of lll_mutex_lock which causes the unlock function to
always wakeup waiters. */
#define lll_mutex_cond_lock(futex) \
@@ -187,6 +216,25 @@ extern int __lll_mutex_unlock_wake (int *__futex)
: "memory"); })
+#define lll_robust_mutex_cond_lock(futex, id) \
+ ({ int result, ignore; \
+ __asm __volatile (LOCK_INSTR "cmpxchgl %1, %2\n\t" \
+ "jnz _L_mutex_cond_lock_%=\n\t" \
+ ".subsection 1\n\t" \
+ ".type _L_mutex_cond_lock_%=,@function\n" \
+ "_L_mutex_cond_lock_%=:\n\t" \
+ "leal %2, %%ecx\n\t" \
+ "call __lll_robust_mutex_lock_wait\n\t" \
+ "jmp 1f\n\t" \
+ ".size _L_mutex_cond_lock_%=,.-_L_mutex_cond_lock_%=\n"\
+ ".previous\n" \
+ "1:" \
+ : "=a" (result), "=c" (ignore), "=m" (futex) \
+ : "0" (0), "1" (id | FUTEX_WAITERS), "m" (futex) \
+ : "memory"); \
+ result; })
+
+
#define lll_mutex_timedlock(futex, timeout) \
({ int result, ignore1, ignore2; \
__asm __volatile (LOCK_INSTR "cmpxchgl %1, %3\n\t" \
@@ -208,9 +256,30 @@ extern int __lll_mutex_unlock_wake (int *__futex)
result; })
+#define lll_robust_mutex_timedlock(futex, timeout, id) \
+ ({ int result, ignore1, ignore2; \
+ __asm __volatile (LOCK_INSTR "cmpxchgl %1, %3\n\t" \
+ "jnz _L_mutex_timedlock_%=\n\t" \
+ ".subsection 1\n\t" \
+ ".type _L_mutex_timedlock_%=,@function\n" \
+ "_L_mutex_timedlock_%=:\n\t" \
+ "leal %3, %%ecx\n\t" \
+ "movl %7, %%edx\n\t" \
+ "call __lll_robust_mutex_timedlock_wait\n\t" \
+ "jmp 1f\n\t" \
+ ".size _L_mutex_timedlock_%=,.-_L_mutex_timedlock_%=\n"\
+ ".previous\n" \
+ "1:" \
+ : "=a" (result), "=c" (ignore1), "=&d" (ignore2), \
+ "=m" (futex) \
+ : "0" (0), "1" (id), "m" (futex), "m" (timeout) \
+ : "memory"); \
+ result; })
+
+
#define lll_mutex_unlock(futex) \
(void) ({ int ignore; \
- __asm __volatile (LOCK_INSTR "subl $1,%0\n\t" \
+ __asm __volatile (LOCK_INSTR "subl $1, %0\n\t" \
"jne _L_mutex_unlock_%=\n\t" \
".subsection 1\n\t" \
".type _L_mutex_unlock_%=,@function\n" \
@@ -226,6 +295,53 @@ extern int __lll_mutex_unlock_wake (int *__futex)
: "memory"); })
+#define lll_robust_mutex_unlock(futex) \
+ (void) ({ int ignore; \
+ __asm __volatile (LOCK_INSTR "andl %2, %0\n\t" \
+ "jne _L_mutex_unlock_%=\n\t" \
+ ".subsection 1\n\t" \
+ ".type _L_mutex_unlock_%=,@function\n" \
+ "_L_mutex_unlock_%=:\n\t" \
+ "leal %0, %%eax\n\t" \
+ "call __lll_mutex_unlock_wake\n\t" \
+ "jmp 1f\n\t" \
+ ".size _L_mutex_unlock_%=,.-_L_mutex_unlock_%=\n" \
+ ".previous\n" \
+ "1:" \
+ : "=m" (futex), "=&a" (ignore) \
+ : "i" (FUTEX_WAITERS), "m" (futex) \
+ : "memory"); })
+
+
+#define lll_robust_mutex_dead(futex) \
+ (void) ({ int __ignore; \
+ register int _nr asm ("edx") = 1; \
+ __asm __volatile (LOCK_INSTR "orl %5, (%2)\n\t" \
+ LLL_EBX_LOAD \
+ LLL_ENTER_KERNEL \
+ LLL_EBX_LOAD \
+ : "=a" (__ignore) \
+ : "0" (SYS_futex), LLL_EBX_REG (&(futex)), \
+ "c" (FUTEX_WAKE), "d" (_nr), \
+ "i" (FUTEX_OWNER_DIED), \
+ "i" (offsetof (tcbhead_t, sysinfo))); })
+
+
+#define lll_futex_wake(futex, nr) \
+ do { \
+ int __ignore; \
+ register __typeof (nr) _nr asm ("edx") = (nr); \
+ __asm __volatile (LLL_EBX_LOAD \
+ LLL_ENTER_KERNEL \
+ LLL_EBX_LOAD \
+ : "=a" (__ignore) \
+ : "0" (SYS_futex), LLL_EBX_REG (futex), \
+ "c" (FUTEX_WAKE), "d" (_nr), \
+ "i" (0) /* phony, to align next arg's number */, \
+ "i" (offsetof (tcbhead_t, sysinfo))); \
+ } while (0)
+
+
#define lll_mutex_islocked(futex) \
(futex != 0)
diff --git a/nptl/sysdeps/unix/sysv/linux/lowlevelrobustlock.sym b/nptl/sysdeps/unix/sysv/linux/lowlevelrobustlock.sym
new file mode 100644
index 0000000000..2f1e9da52b
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/lowlevelrobustlock.sym
@@ -0,0 +1,6 @@
+#include <stddef.h>
+#include <pthreadP.h>
+
+--
+
+TID offsetof (struct pthread, tid)
diff --git a/nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c b/nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c
index 990db87416..a97351f880 100644
--- a/nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c
+++ b/nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c
@@ -1,7 +1,8 @@
#include <pthreadP.h>
-#define LLL_MUTEX_LOCK(mutex) lll_mutex_cond_lock(mutex)
-#define LLL_MUTEX_TRYLOCK(mutex) lll_mutex_cond_trylock(mutex)
+#define LLL_MUTEX_LOCK(mutex) lll_mutex_cond_lock (mutex)
+#define LLL_MUTEX_TRYLOCK(mutex) lll_mutex_cond_trylock (mutex)
+#define LLL_ROBUST_MUTEX_LOCK(mutex, id) lll_robust_mutex_cond_lock (mutex, id)
#define __pthread_mutex_lock __pthread_mutex_cond_lock
#define NO_INCR
diff --git a/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.h b/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.h
index e3e3777f44..92f93cd5f5 100644
--- a/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.h
+++ b/nptl/sysdeps/unix/sysv/linux/sh/lowlevellock.h
@@ -62,6 +62,28 @@ extern int __lll_mutex_unlock_wake (int *__futex) attribute_hidden;
: "r0", "r1", "r2", "t", "memory"); \
__result; })
+#define lll_robust_mutex_trylock(futex, id) \
+ ({ unsigned char __result; \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ nop\n\
+ mov r15,r1\n\
+ mov #-8,r15\n\
+ 0: mov.l @%1,r2\n\
+ cmp/eq r2,%3\n\
+ bf 1f\n\
+ mov.l %2,@%1\n\
+ 1: mov r1,r15\n\
+ mov #-1,%0\n\
+ negc %0,%0"\
+ : "=r" (__result) \
+ : "r" (&(futex)), \
+ "r" (id), \
+ "r" (LLL_MUTEX_LOCK_INITIALIZER) \
+ : "r0", "r1", "r2", "t", "memory"); \
+ __result; })
+
#define lll_mutex_cond_trylock(futex) \
({ unsigned char __result; \
__asm __volatile ("\
@@ -102,6 +124,25 @@ extern int __lll_mutex_unlock_wake (int *__futex) attribute_hidden;
if (__result) \
__lll_mutex_lock_wait (__result, __futex); })
+#define lll_robust_mutex_lock(futex, id) \
+ ({ int __result, val, *__futex = &(futex); \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ nop\n\
+ mov r15,r1\n\
+ mov #-8,r15\n\
+ 0: mov.l @%2,%0\n\
+ tst %0,%0\n\
+ bf 1f\n\
+ mov.l %1,@%2\n\
+ 1: mov r1,r15"\
+ : "=&r" (__result) : "r" (id), "r" (__futex) \
+ : "r0", "r1", "t", "memory"); \
+ if (__result) \
+ __result = __lll_robust_mutex_lock_wait (__result, __futex); \
+ __result; })
+
/* Special version of lll_mutex_lock which causes the unlock function to
always wakeup waiters. */
#define lll_mutex_cond_lock(futex) \
@@ -122,6 +163,25 @@ extern int __lll_mutex_unlock_wake (int *__futex) attribute_hidden;
if (__result) \
__lll_mutex_lock_wait (__result, __futex); })
+#define lll_robust_mutex_cond_lock(futex, id) \
+ ({ int __result, val, *__futex = &(futex); \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ nop\n\
+ mov r15,r1\n\
+ mov #-8,r15\n\
+ 0: mov.l @%2,%0\n\
+ tst %0,%0\n\
+ bf 1f\n\
+ mov.l %1,@%2\n\
+ 1: mov r1,r15"\
+ : "=&r" (__result) : "r" (id | FUTEX_WAITERS), "r" (__futex) \
+ : "r0", "r1", "t", "memory"); \
+ if (__result) \
+ __result = __lll_robust_mutex_lock_wait (__result, __futex); \
+ __result; })
+
#define lll_mutex_timedlock(futex, timeout) \
({ int __result, val, *__futex = &(futex); \
__asm __volatile ("\
@@ -141,6 +201,26 @@ extern int __lll_mutex_unlock_wake (int *__futex) attribute_hidden;
__result = __lll_mutex_timedlock_wait (__result, __futex, timeout); \
__result; })
+#define lll_robust_mutex_timedlock(futex, timeout, id) \
+ ({ int __result, val, *__futex = &(futex); \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ nop\n\
+ mov r15,r1\n\
+ mov #-8,r15\n\
+ 0: mov.l @%2,%0\n\
+ tst %0,%0\n\
+ bf 1f\n\
+ mov.l %1,@%2\n\
+ 1: mov r1,r15"\
+ : "=&r" (__result) : "r" (id), "r" (__futex) \
+ : "r0", "r1", "t", "memory"); \
+ if (__result) \
+ __result = __lll_robust_mutex_timedlock_wait (__result, __futex, \
+ timeout); \
+ __result; })
+
#define lll_mutex_unlock(futex) \
(void) ({ int __result, *__futex = &(futex); \
__asm __volatile ("\
@@ -157,6 +237,37 @@ extern int __lll_mutex_unlock_wake (int *__futex) attribute_hidden;
if (__result) \
__lll_mutex_unlock_wake (__futex); })
+#define lll_robust_mutex_unlock(futex) \
+ (void) ({ int __result, *__futex = &(futex); \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ mov r15,r1\n\
+ mov #-6,r15\n\
+ 0: mov.l @%1,%0\n\
+ and %2,%0\n\
+ mov.l %0,@%1\n\
+ 1: mov r1,r15"\
+ : "=&r" (__result) : "r" (__futex), "r" (FUTEX_TID_MASK) \
+ : "r0", "r1", "memory"); \
+ if (__result) \
+ __lll_mutex_unlock_wake (__futex); })
+
+#define lll_robust_mutex_dead(futex) \
+ (void) ({ int __ignore, *__futex = &(futex); \
+ __asm __volatile ("\
+ .align 2\n\
+ mova 1f,r0\n\
+ mov r15,r1\n\
+ mov #-6,r15\n\
+ 0: mov.l @%1,%0\n\
+ or %2,%0\n\
+ mov.l %0,@%1\n\
+ 1: mov r1,r15"\
+ : "=&r" (__ignore) : "r" (__futex), "r" (FUTEX_OWNER_DIED) \
+ : "r0", "r1", "memory"); \
+ lll_futex_wake (__futex, 1); })
+
#define lll_mutex_islocked(futex) \
(futex != 0)
diff --git a/nptl/sysdeps/unix/sysv/linux/sh/lowlevelrobustlock.S b/nptl/sysdeps/unix/sysv/linux/sh/lowlevelrobustlock.S
new file mode 100644
index 0000000000..c57d3cff18
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/sh/lowlevelrobustlock.S
@@ -0,0 +1,224 @@
+/* Copyright (C) 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
+ 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 <sysdep.h>
+#include <pthread-errnos.h>
+#include <lowlevelrobustlock.h>
+#include "lowlevel-atomic.h"
+
+ .text
+
+#define SYS_gettimeofday __NR_gettimeofday
+#define SYS_futex 240
+#define FUTEX_WAIT 0
+#define FUTEX_WAKE 1
+#define FUTEX_WAITERS 0x80000000
+#define FUTEX_OWNER_DIED 0x40000000
+
+
+ .globl __lll_robust_mutex_lock_wait
+ .type __lll_robust_mutex_lock_wait,@function
+ .hidden __lll_robust_mutex_lock_wait
+ .align 5
+ cfi_startproc
+__lll_robust_mutex_lock_wait:
+ mov.l r8, @-r15
+ cfi_adjust_cfa_offset(4)
+ cfi_rel_offset (r8, 0)
+ mov r5, r8
+ mov #0, r7 /* No timeout. */
+ mov #FUTEX_WAIT, r5
+
+4:
+ mov r4, r6
+ mov.l .L_FUTEX_WAITERS, r0
+ or r0, r6
+ shlr r0 /* r0 = FUTEX_OWNER_DIED */
+ tst r0, r4
+ bf/s 3f
+ cmp/eq r4, r6
+ bt 1f
+
+ CMPXCHG (r4, @r8, r6, r2)
+ bf 2f
+
+1:
+ mov r8, r4
+ mov #SYS_futex, r3
+ extu.b r3, r3
+ trapa #0x14
+ SYSCALL_INST_PAD
+
+ mov.l @r8, r2
+
+2:
+ tst r2, r2
+ bf/s 4b
+ mov r2, r4
+
+ stc gbr, r1
+ mov.w .Ltidoff, r2
+ add r2, r1
+ mov.l @r1, r6
+ mov #0, r3
+ CMPXCHG (r3, @r8, r6, r4)
+ bf 4b
+ mov #0, r4
+
+3:
+ mov.l @r15+, r8
+ ret
+ mov r4, r0
+ cfi_endproc
+ .align 2
+.L_FUTEX_WAITERS:
+ .long FUTEX_WAITERS
+.Ltidoff:
+ .word TID - TLS_PRE_TCB_SIZE
+ .size __lll_robust_mutex_lock_wait,.-__lll_robust_mutex_lock_wait
+
+
+ .globl __lll_robust_mutex_timedlock_wait
+ .type __lll_robust_mutex_timedlock_wait,@function
+ .hidden __lll_robust_mutex_timedlock_wait
+ .align 5
+ cfi_startproc
+__lll_robust_mutex_timedlock_wait:
+ /* Check for a valid timeout value. */
+ mov.l @(4,r6), r1
+ mov.l .L1g, r0
+ cmp/hs r0, r1
+ bt 3f
+
+ mov.l r10, @-r15
+ cfi_adjust_cfa_offset(4)
+ cfi_rel_offset (r10, 0)
+ mov.l r9, @-r15
+ cfi_adjust_cfa_offset(4)
+ cfi_rel_offset (r9, 0)
+ mov.l r8, @-r15
+ cfi_adjust_cfa_offset(4)
+ cfi_rel_offset (r8, 0)
+ mov r4, r10
+ mov r6, r9
+ mov r5, r8
+
+ /* Stack frame for the timespec and timeval structs. */
+ add #-8, r15
+ cfi_adjust_cfa_offset(8)
+
+1:
+ /* Get current time. */
+ mov r15, r4
+ mov #0, r5
+ mov #SYS_gettimeofday, r3
+ trapa #0x12
+ SYSCALL_INST_PAD
+
+ /* Compute relative timeout. */
+ mov.l @(4,r15), r0
+ mov.w .L1k, r1
+ dmulu.l r0, r1 /* Micro seconds to nano seconds. */
+ mov.l @r9, r2
+ mov.l @(4,r9), r3
+ mov.l @r15, r0
+ sts macl, r1
+ sub r0, r2
+ clrt
+ subc r1, r3
+ bf 4f
+ mov.l .L1g, r1
+ add r1, r3
+ add #-1, r2
+4:
+ cmp/pz r2
+ bf 8f /* Time is already up. */
+
+ mov.l r2, @r15 /* Store relative timeout. */
+ mov.l r3, @(4,r15)
+
+ mov r10, r6
+ mov.l .L_FUTEX_WAITERS2, r0
+ or r0, r6
+ shlr r0 /* r0 = FUTEX_OWNER_DIED */
+ tst r0, r4
+ bf/s 6f
+ cmp/eq r4, r6
+ bt 2f
+
+ CMPXCHG (r4, @r8, r6, r2)
+ bf/s 5f
+ mov #0, r5
+
+2:
+ mov r8, r4
+ mov #FUTEX_WAIT, r5
+ mov r10, r6
+ mov r15, r7
+ mov #SYS_futex, r3
+ extu.b r3, r3
+ trapa #0x14
+ SYSCALL_INST_PAD
+ mov r0, r5
+
+ mov.l @r8, r2
+
+5:
+ tst r2, r2
+ bf/s 7f
+ mov r2, r10
+
+ stc gbr, r1
+ mov.w .Ltidoff2, r2
+ add r2, r1
+ mov.l @r1, r4
+ mov #0, r3
+ CMPXCHG (r3, @r8, r4, r10)
+ bf 7f
+ mov #0, r0
+
+6:
+ add #8, r15
+ mov.l @r15+, r8
+ mov.l @r15+, r9
+ rts
+ mov.l @r15+, r10
+
+7:
+ /* Check whether the time expired. */
+ mov #-ETIMEDOUT, r1
+ cmp/eq r5, r1
+ bf 1b
+
+8:
+ bra 6b
+ mov #ETIMEDOUT, r0
+3:
+ rts
+ mov #EINVAL, r0
+ cfi_endproc
+ .align 2
+.L_FUTEX_WAITERS2:
+ .long FUTEX_WAITERS
+.L1g:
+ .long 1000000000
+.Ltidoff2:
+ .word TID - TLS_PRE_TCB_SIZE
+.L1k:
+ .word 1000
+ .size __lll_robust_mutex_timedlock_wait,.-__lll_robust_mutex_timedlock_wait
diff --git a/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h b/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h
index ebcfe6eef1..95e6923d4d 100644
--- a/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h
+++ b/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h
@@ -111,6 +111,16 @@ extern int __lll_mutex_unlock_wait (int *__futex) attribute_hidden;
ret; })
+#define lll_robust_mutex_trylock(futex, id) \
+ ({ int ret; \
+ __asm __volatile (LOCK_INSTR "cmpxchgl %2, %1" \
+ : "=a" (ret), "=m" (futex) \
+ : "r" (id), "m" (futex), \
+ "0" (LLL_MUTEX_LOCK_INITIALIZER) \
+ : "memory"); \
+ ret; })
+
+
#define lll_mutex_cond_trylock(futex) \
({ int ret; \
__asm __volatile (LOCK_INSTR "cmpxchgl %2, %1" \
@@ -139,6 +149,25 @@ extern int __lll_mutex_unlock_wait (int *__futex) attribute_hidden;
: "cx", "r11", "cc", "memory"); })
+#define lll_robust_mutex_lock(futex, id) \
+ ({ int result, ignore1, ignore2; \
+ __asm __volatile (LOCK_INSTR "cmpxchgl %0, %2\n\t" \
+ "jnz 1f\n\t" \
+ ".subsection 1\n" \
+ "1:\tleaq %2, %%rdi\n\t" \
+ "subq $128, %%rsp\n\t" \
+ "callq __lll_robust_mutex_lock_wait\n\t" \
+ "addq $128, %%rsp\n\t" \
+ "jmp 2f\n\t" \
+ ".previous\n" \
+ "2:" \
+ : "=S" (ignore1), "=&D" (ignore2), "=m" (futex), \
+ "=a" (result) \
+ : "0" (id), "m" (futex), "3" (0) \
+ : "cx", "r11", "cc", "memory"); \
+ result; })
+
+
#define lll_mutex_cond_lock(futex) \
(void) ({ int ignore1, ignore2, ignore3; \
__asm __volatile (LOCK_INSTR "cmpxchgl %0, %2\n\t" \
@@ -157,6 +186,25 @@ extern int __lll_mutex_unlock_wait (int *__futex) attribute_hidden;
: "cx", "r11", "cc", "memory"); })
+#define lll_robust_mutex_cond_lock(futex, id) \
+ ({ int result, ignore1, ignore2; \
+ __asm __volatile (LOCK_INSTR "cmpxchgl %0, %2\n\t" \
+ "jnz 1f\n\t" \
+ ".subsection 1\n" \
+ "1:\tleaq %2, %%rdi\n\t" \
+ "subq $128, %%rsp\n\t" \
+ "callq __lll_robust_mutex_lock_wait\n\t" \
+ "addq $128, %%rsp\n\t" \
+ "jmp 2f\n\t" \
+ ".previous\n" \
+ "2:" \
+ : "=S" (ignore1), "=&D" (ignore2), "=m" (futex), \
+ "=a" (result) \
+ : "0" (id | FUTEX_WAITERS), "m" (futex), "3" (0) \
+ : "cx", "r11", "cc", "memory"); \
+ result; })
+
+
#define lll_mutex_timedlock(futex, timeout) \
({ int result, ignore1, ignore2, ignore3; \
__asm __volatile (LOCK_INSTR "cmpxchgl %2, %4\n\t" \
@@ -177,6 +225,26 @@ extern int __lll_mutex_unlock_wait (int *__futex) attribute_hidden;
result; })
+#define lll_robust_mutex_timedlock(futex, timeout, id) \
+ ({ int result, ignore1, ignore2, ignore3; \
+ __asm __volatile (LOCK_INSTR "cmpxchgl %2, %4\n\t" \
+ "jnz 1f\n\t" \
+ ".subsection 1\n" \
+ "1:\tleaq %4, %%rdi\n\t" \
+ "movq %8, %%rdx\n\t" \
+ "subq $128, %%rsp\n\t" \
+ "callq __lll_robust_mutex_timedlock_wait\n\t" \
+ "addq $128, %%rsp\n\t" \
+ "jmp 2f\n\t" \
+ ".previous\n" \
+ "2:" \
+ : "=a" (result), "=&D" (ignore1), "=S" (ignore2), \
+ "=&d" (ignore3), "=m" (futex) \
+ : "0" (0), "2" (id), "m" (futex), "m" (timeout) \
+ : "memory", "cx", "cc", "r10", "r11"); \
+ result; })
+
+
#define lll_mutex_unlock(futex) \
(void) ({ int ignore; \
__asm __volatile (LOCK_INSTR "decl %0\n\t" \
@@ -194,6 +262,34 @@ extern int __lll_mutex_unlock_wait (int *__futex) attribute_hidden;
: "ax", "cx", "r11", "cc", "memory"); })
+#define lll_robust_mutex_unlock(futex) \
+ (void) ({ int ignore; \
+ __asm __volatile (LOCK_INSTR "andl %2, %0\n\t" \
+ "jne 1f\n\t" \
+ ".subsection 1\n" \
+ "1:\tleaq %0, %%rdi\n\t" \
+ "subq $128, %%rsp\n\t" \
+ "callq __lll_mutex_unlock_wake\n\t" \
+ "addq $128, %%rsp\n\t" \
+ "jmp 2f\n\t" \
+ ".previous\n" \
+ "2:" \
+ : "=m" (futex), "=&D" (ignore) \
+ : "i" (FUTEX_WAITERS), "m" (futex) \
+ : "ax", "cx", "r11", "cc", "memory"); })
+
+
+#define lll_robust_mutex_dead(futex) \
+ (void) ({ int ignore; \
+ __asm __volatile (LOCK_INSTR "orl %3, (%2)\n\t" \
+ "syscall" \
+ : "=m" (futex), "=a" (ignore) \
+ : "D" (&(futex)), "i" (FUTEX_OWNER_DIED), \
+ "S" (FUTEX_WAKE), "1" (__NR_futex), \
+ "d" (1) \
+ : "cx", "r11", "cc", "memory"); })
+
+
#define lll_mutex_islocked(futex) \
(futex != LLL_MUTEX_LOCK_INITIALIZER)
diff --git a/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.S b/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.S
new file mode 100644
index 0000000000..7bb9191691
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevelrobustlock.S
@@ -0,0 +1,192 @@
+/* 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.
+
+ 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 <sysdep.h>
+#include <pthread-errnos.h>
+#include <lowlevelrobustlock.h>
+
+ .text
+
+#ifndef LOCK
+# ifdef UP
+# define LOCK
+# else
+# define LOCK lock
+# endif
+#endif
+
+#define SYS_futex 202
+#define FUTEX_WAIT 0
+#define FUTEX_WAKE 1
+#define FUTEX_WAITERS 0x80000000
+#define FUTEX_OWNER_DIED 0x40000000
+
+/* For the calculation see asm/vsyscall.h. */
+#define VSYSCALL_ADDR_vgettimeofday 0xffffffffff600000
+
+
+ .globl __lll_robust_mutex_lock_wait
+ .type __lll_robust_mutex_lock_wait,@function
+ .hidden __lll_robust_mutex_lock_wait
+ .align 16
+__lll_robust_mutex_lock_wait:
+ pushq %r10
+ pushq %rdx
+
+ xorq %r10, %r10 /* No timeout. */
+#if FUTEX_WAIT == 0
+ xorl %esi, %esi
+#else
+ movl $FUTEX_WAIT, %esi
+#endif
+
+4: movl %eax, %edx
+ orl $FUTEX_WAITERS, %edx
+
+ testl $FUTEX_OWNER_DIED, %eax
+ jnz 3f
+
+ cmpl %edx, %eax
+ je 1f
+
+ LOCK
+ cmpxchgl %edx, (%rdi)
+ jnz 2f
+
+1: movl $SYS_futex, %eax
+ syscall
+
+ movl (%rdi), %eax
+
+2: testl %eax, %eax
+ jne 4b
+
+ movl %fs:TID, %edx
+ LOCK
+ cmpxchgl %edx, (%rdi)
+ jnz 4b
+ /* NB: %rax == 0 */
+
+3: popq %rdx
+ popq %r10
+ retq
+ .size __lll_robust_mutex_lock_wait,.-__lll_robust_mutex_lock_wait
+
+
+ .globl __lll_robust_mutex_timedlock_wait
+ .type __lll_robust_mutex_timedlock_wait,@function
+ .hidden __lll_robust_mutex_timedlock_wait
+ .align 16
+__lll_robust_mutex_timedlock_wait:
+ /* Check for a valid timeout value. */
+ cmpq $1000000000, 8(%rdx)
+ jae 3f
+
+ pushq %r8
+ pushq %r9
+ pushq %r12
+ pushq %r13
+
+ /* Stack frame for the timespec and timeval structs. */
+ subq $24, %rsp
+
+ movq %rdi, %r12
+ movq %rdx, %r13
+
+1: movq %rax, 16(%rsp)
+
+ /* Get current time. */
+ movq %rsp, %rdi
+ xorl %esi, %esi
+ movq $VSYSCALL_ADDR_vgettimeofday, %rax
+ /* This is a regular function call, all caller-save registers
+ might be clobbered. */
+ callq *%rax
+
+ /* Compute relative timeout. */
+ movq 8(%rsp), %rax
+ movl $1000, %edi
+ mul %rdi /* Milli seconds to nano seconds. */
+ movq (%r13), %rdi
+ movq 8(%r13), %rsi
+ subq (%rsp), %rdi
+ subq %rax, %rsi
+ jns 4f
+ addq $1000000000, %rsi
+ decq %rdi
+4: testq %rdi, %rdi
+ js 8f /* Time is already up. */
+
+ /* Futex call. */
+ movq %rdi, (%rsp) /* Store relative timeout. */
+ movq %rsi, 8(%rsp)
+
+ movq 16(%rsp), %rdx
+ movl %edx, %eax
+ orl $FUTEX_WAITERS, %edx
+
+ testl $FUTEX_OWNER_DIED, %eax
+ jnz 6f
+
+ cmpl %eax, %edx
+ je 2f
+
+ LOCK
+ cmpxchgl %edx, (%r12)
+ movq $0, %rcx /* Must use mov to avoid changing cc. */
+ jnz 5f
+
+2: movq %rsp, %r10
+#if FUTEX_WAIT == 0
+ xorl %esi, %esi
+#else
+ movl $FUTEX_WAIT, %esi
+#endif
+ movq %r12, %rdi
+ movl $SYS_futex, %eax
+ syscall
+ movq %rax, %rcx
+
+ movl (%r12), %eax
+
+5: testl %eax, %eax
+ jne 7f
+
+ movl %fs:TID, %edx
+ LOCK
+ cmpxchgl %edx, (%r12)
+ jnz 7f
+
+6: addq $24, %rsp
+ popq %r13
+ popq %r12
+ popq %r9
+ popq %r8
+ retq
+
+ /* Check whether the time expired. */
+7: cmpq $-ETIMEDOUT, %rcx
+ jne 1b
+
+8: movl $ETIMEDOUT, %eax
+ jmp 6b
+
+3: movl $EINVAL, %eax
+ retq
+ .size __lll_robust_mutex_timedlock_wait,.-__lll_robust_mutex_timedlock_wait
diff --git a/sysdeps/unix/sysv/linux/alpha/bits/mman.h b/sysdeps/unix/sysv/linux/alpha/bits/mman.h
index 8ef939aeb3..2a84709d20 100644
--- a/sysdeps/unix/sysv/linux/alpha/bits/mman.h
+++ b/sysdeps/unix/sysv/linux/alpha/bits/mman.h
@@ -97,6 +97,8 @@
# define MADV_WILLNEED 3 /* Will need these pages. */
# define MADV_DONTNEED 6 /* Don't need these pages. */
# define MADV_REMOVE 7 /* Remove these pages and resources. */
+# define MADV_DONTFORK 10 /* Do not inherit across fork. */
+# define MADV_DOFORK 11 /* Do inherit across fork. */
#endif
/* The POSIX people had to invent similar names for the same things. */
diff --git a/sysdeps/unix/sysv/linux/i386/bits/mman.h b/sysdeps/unix/sysv/linux/i386/bits/mman.h
index 1c4ffbf581..f198fa4b91 100644
--- a/sysdeps/unix/sysv/linux/i386/bits/mman.h
+++ b/sysdeps/unix/sysv/linux/i386/bits/mman.h
@@ -89,6 +89,8 @@
# define MADV_WILLNEED 3 /* Will need these pages. */
# define MADV_DONTNEED 4 /* Don't need these pages. */
# define MADV_REMOVE 5 /* Remove these pages and resources. */
+# define MADV_DONTFORK 10 /* Do not inherit across fork. */
+# define MADV_DOFORK 11 /* Do inherit across fork. */
#endif
/* The POSIX people had to invent similar names for the same things. */
diff --git a/sysdeps/unix/sysv/linux/ia64/bits/mman.h b/sysdeps/unix/sysv/linux/ia64/bits/mman.h
index 10bf9632c5..86344962af 100644
--- a/sysdeps/unix/sysv/linux/ia64/bits/mman.h
+++ b/sysdeps/unix/sysv/linux/ia64/bits/mman.h
@@ -90,6 +90,8 @@
# define MADV_WILLNEED 3 /* Will need these pages. */
# define MADV_DONTNEED 4 /* Don't need these pages. */
# define MADV_REMOVE 5 /* Remove these pages and resources. */
+# define MADV_DONTFORK 10 /* Do not inherit across fork. */
+# define MADV_DOFORK 11 /* Do inherit across fork. */
#endif
/* The POSIX people had to invent similar names for the same things. */
diff --git a/sysdeps/unix/sysv/linux/m68k/bits/mman.h b/sysdeps/unix/sysv/linux/m68k/bits/mman.h
index 6e7bdc99dd..fbec1a03f8 100644
--- a/sysdeps/unix/sysv/linux/m68k/bits/mman.h
+++ b/sysdeps/unix/sysv/linux/m68k/bits/mman.h
@@ -88,6 +88,8 @@
# define MADV_SEQUENTIAL 2 /* Expect sequential page references. */
# define MADV_WILLNEED 3 /* Will need these pages. */
# define MADV_DONTNEED 4 /* Don't need these pages. */
+# define MADV_DONTFORK 10 /* Do not inherit across fork. */
+# define MADV_DOFORK 11 /* Do inherit across fork. */
#endif
/* The POSIX people had to invent similar names for the same things. */
diff --git a/sysdeps/unix/sysv/linux/not-cancel.h b/sysdeps/unix/sysv/linux/not-cancel.h
index ece8d69ecf..4a76335a55 100644
--- a/sysdeps/unix/sysv/linux/not-cancel.h
+++ b/sysdeps/unix/sysv/linux/not-cancel.h
@@ -28,18 +28,26 @@
INLINE_SYSCALL (open, 2, (const char *) (name), (flags))
/* Uncancelable openat. */
-extern int __openat_not_cancel (int fd, const char *fname, int oflag,
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+extern int __openat_nocancel (int fd, const char *fname, int oflag,
+ mode_t mode) attribute_hidden;
+extern int __openat64_nocancel (int fd, const char *fname, int oflag,
mode_t mode) attribute_hidden;
+#else
+# define __openat_nocancel(fd, fname, oflag, mode) \
+ openat (fd, fname, oflag, mode)
+# define __openat64_nocancel(fd, fname, oflag, mode) \
+ openat64 (fd, fname, oflag, mode)
+#endif
+
#define openat_not_cancel(fd, fname, oflag, mode) \
- __openat_not_cancel (fd, fname, oflag, mode)
+ __openat_nocancel (fd, fname, oflag, mode)
#define openat_not_cancel_3(fd, fname, oflag) \
- __openat_not_cancel (fd, fname, oflag, 0)
-extern int __openat64_not_cancel (int fd, const char *fname, int oflag,
- mode_t mode) attribute_hidden;
+ __openat_nocancel (fd, fname, oflag, 0)
#define openat64_not_cancel(fd, fname, oflag, mode) \
- __openat64_not_cancel (fd, fname, oflag, mode)
+ __openat64_nocancel (fd, fname, oflag, mode)
#define openat64_not_cancel_3(fd, fname, oflag) \
- __openat64_not_cancel (fd, fname, oflag, 0)
+ __openat64_nocancel (fd, fname, oflag, 0)
/* Uncancelable close. */
#define close_not_cancel(fd) \
diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/mman.h b/sysdeps/unix/sysv/linux/powerpc/bits/mman.h
index 22ebfd120f..580e93886f 100644
--- a/sysdeps/unix/sysv/linux/powerpc/bits/mman.h
+++ b/sysdeps/unix/sysv/linux/powerpc/bits/mman.h
@@ -90,6 +90,8 @@
# define MADV_WILLNEED 3 /* Will need these pages. */
# define MADV_DONTNEED 4 /* Don't need these pages. */
# define MADV_REMOVE 5 /* Remove these pages and resources. */
+# define MADV_DONTFORK 10 /* Do not inherit across fork. */
+# define MADV_DOFORK 11 /* Do inherit across fork. */
#endif
/* The POSIX people had to invent similar names for the same things. */
diff --git a/sysdeps/unix/sysv/linux/s390/bits/mman.h b/sysdeps/unix/sysv/linux/s390/bits/mman.h
index acedbf0f5d..f248929824 100644
--- a/sysdeps/unix/sysv/linux/s390/bits/mman.h
+++ b/sysdeps/unix/sysv/linux/s390/bits/mman.h
@@ -90,6 +90,8 @@
# define MADV_WILLNEED 3 /* Will need these pages. */
# define MADV_DONTNEED 4 /* Don't need these pages. */
# define MADV_REMOVE 5 /* Remove these pages and resources. */
+# define MADV_DONTFORK 10 /* Do not inherit across fork. */
+# define MADV_DOFORK 11 /* Do inherit across fork. */
#endif
/* The POSIX people had to invent similar names for the same things. */
diff --git a/sysdeps/unix/sysv/linux/sh/bits/mman.h b/sysdeps/unix/sysv/linux/sh/bits/mman.h
index 11067c5209..3c10334a4b 100644
--- a/sysdeps/unix/sysv/linux/sh/bits/mman.h
+++ b/sysdeps/unix/sysv/linux/sh/bits/mman.h
@@ -89,6 +89,8 @@
# define MADV_WILLNEED 3 /* Will need these pages. */
# define MADV_DONTNEED 4 /* Don't need these pages. */
# define MADV_REMOVE 5 /* Remove these pages and resources. */
+# define MADV_DONTFORK 10 /* Do not inherit across fork. */
+# define MADV_DOFORK 11 /* Do inherit across fork. */
#endif
/* The POSIX people had to invent similar names for the same things. */
diff --git a/sysdeps/unix/sysv/linux/sparc/bits/mman.h b/sysdeps/unix/sysv/linux/sparc/bits/mman.h
index 7c8689f223..8de270f932 100644
--- a/sysdeps/unix/sysv/linux/sparc/bits/mman.h
+++ b/sysdeps/unix/sysv/linux/sparc/bits/mman.h
@@ -92,6 +92,8 @@
# define MADV_DONTNEED 4 /* Don't need these pages. */
# define MADV_FREE 5 /* Content can be freed (Solaris). */
# define MADV_REMOVE 6 /* Remove these pages and resources. */
+# define MADV_DONTFORK 10 /* Do not inherit across fork. */
+# define MADV_DOFORK 11 /* Do inherit across fork. */
#endif
/* The POSIX people had to invent similar names for the same things. */
diff --git a/sysdeps/unix/sysv/linux/x86_64/bits/mman.h b/sysdeps/unix/sysv/linux/x86_64/bits/mman.h
index b1a8b93d36..8803900552 100644
--- a/sysdeps/unix/sysv/linux/x86_64/bits/mman.h
+++ b/sysdeps/unix/sysv/linux/x86_64/bits/mman.h
@@ -90,6 +90,8 @@
# define MADV_WILLNEED 3 /* Will need these pages. */
# define MADV_DONTNEED 4 /* Don't need these pages. */
# define MADV_REMOVE 5 /* Remove these pages and resources. */
+# define MADV_DONTFORK 10 /* Do not inherit across fork. */
+# define MADV_DOFORK 11 /* Do inherit across fork. */
#endif
/* The POSIX people had to invent similar names for the same things. */