about summary refs log tree commit diff
path: root/nptl/pthread_mutex_timedlock.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_timedlock.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_timedlock.c')
-rw-r--r--nptl/pthread_mutex_timedlock.c150
1 files changed, 147 insertions, 3 deletions
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;