about summary refs log tree commit diff
path: root/nptl/pthread_mutex_lock.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2006-07-29 04:42:09 +0000
committerUlrich Drepper <drepper@redhat.com>2006-07-29 04:42:09 +0000
commitdf47504c78f82b9c975b2a48a6c8b6dd73a79ce1 (patch)
tree6706cdb46e20a69b3a4b4bffa9a29db9eeaff9c2 /nptl/pthread_mutex_lock.c
parent6822f05652c50c63cdaacffd41b5ad2db0f027ce (diff)
downloadglibc-df47504c78f82b9c975b2a48a6c8b6dd73a79ce1.tar.gz
glibc-df47504c78f82b9c975b2a48a6c8b6dd73a79ce1.tar.xz
glibc-df47504c78f82b9c975b2a48a6c8b6dd73a79ce1.zip
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/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.
Diffstat (limited to 'nptl/pthread_mutex_lock.c')
-rw-r--r--nptl/pthread_mutex_lock.c129
1 files changed, 129 insertions, 0 deletions
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;