Blame nptl/pthread_mutex_trylock.c

Packit 6c4009
/* Copyright (C) 2002-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include "pthreadP.h"
Packit 6c4009
#include <lowlevellock.h>
Packit 6c4009
Packit 6c4009
#ifndef lll_trylock_elision
Packit 6c4009
#define lll_trylock_elision(a,t) lll_trylock(a)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef FORCE_ELISION
Packit 6c4009
#define FORCE_ELISION(m, s)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
__pthread_mutex_trylock (pthread_mutex_t *mutex)
Packit 6c4009
{
Packit 6c4009
  int oldval;
Packit 6c4009
  pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
Packit 6c4009
Packit Bot 45699f
  /* See concurrency notes regarding mutex type which is loaded from __kind
Packit Bot 45699f
     in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h.  */
Packit 6c4009
  switch (__builtin_expect (PTHREAD_MUTEX_TYPE_ELISION (mutex),
Packit 6c4009
			    PTHREAD_MUTEX_TIMED_NP))
Packit 6c4009
    {
Packit 6c4009
      /* Recursive mutex.  */
Packit 6c4009
    case PTHREAD_MUTEX_RECURSIVE_NP|PTHREAD_MUTEX_ELISION_NP:
Packit 6c4009
    case PTHREAD_MUTEX_RECURSIVE_NP:
Packit 6c4009
      /* Check whether we already hold the mutex.  */
Packit 6c4009
      if (mutex->__data.__owner == id)
Packit 6c4009
	{
Packit 6c4009
	  /* Just bump the counter.  */
Packit 6c4009
	  if (__glibc_unlikely (mutex->__data.__count + 1 == 0))
Packit 6c4009
	    /* Overflow of the counter.  */
Packit 6c4009
	    return EAGAIN;
Packit 6c4009
Packit 6c4009
	  ++mutex->__data.__count;
Packit 6c4009
	  return 0;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (lll_trylock (mutex->__data.__lock) == 0)
Packit 6c4009
	{
Packit 6c4009
	  /* Record the ownership.  */
Packit 6c4009
	  mutex->__data.__owner = id;
Packit 6c4009
	  mutex->__data.__count = 1;
Packit 6c4009
	  ++mutex->__data.__nusers;
Packit 6c4009
	  return 0;
Packit 6c4009
	}
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case PTHREAD_MUTEX_TIMED_ELISION_NP:
Packit 6c4009
    elision: __attribute__((unused))
Packit 6c4009
      if (lll_trylock_elision (mutex->__data.__lock,
Packit 6c4009
			       mutex->__data.__elision) != 0)
Packit 6c4009
	break;
Packit 6c4009
      /* Don't record the ownership.  */
Packit 6c4009
      return 0;
Packit 6c4009
Packit 6c4009
    case PTHREAD_MUTEX_TIMED_NP:
Packit 6c4009
      FORCE_ELISION (mutex, goto elision);
Packit 6c4009
      /*FALL THROUGH*/
Packit 6c4009
    case PTHREAD_MUTEX_ADAPTIVE_NP:
Packit 6c4009
    case PTHREAD_MUTEX_ERRORCHECK_NP:
Packit 6c4009
      if (lll_trylock (mutex->__data.__lock) != 0)
Packit 6c4009
	break;
Packit 6c4009
Packit 6c4009
      /* Record the ownership.  */
Packit 6c4009
      mutex->__data.__owner = id;
Packit 6c4009
      ++mutex->__data.__nusers;
Packit 6c4009
Packit 6c4009
      return 0;
Packit 6c4009
Packit 6c4009
    case PTHREAD_MUTEX_ROBUST_RECURSIVE_NP:
Packit 6c4009
    case PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP:
Packit 6c4009
    case PTHREAD_MUTEX_ROBUST_NORMAL_NP:
Packit 6c4009
    case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP:
Packit 6c4009
      THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
Packit 6c4009
		     &mutex->__data.__list.__next);
Packit Bot cfd2ea
      /* We need to set op_pending before starting the operation.  Also
Packit Bot cfd2ea
	 see comments at ENQUEUE_MUTEX.  */
Packit Bot cfd2ea
      __asm ("" ::: "memory");
Packit 6c4009
Packit 6c4009
      oldval = mutex->__data.__lock;
Packit 6c4009
      do
Packit 6c4009
	{
Packit 6c4009
	again:
Packit 6c4009
	  if ((oldval & FUTEX_OWNER_DIED) != 0)
Packit 6c4009
	    {
Packit 6c4009
	      /* The previous owner died.  Try locking the mutex.  */
Packit 6c4009
	      int newval = id | (oldval & FUTEX_WAITERS);
Packit 6c4009
Packit 6c4009
	      newval
Packit 6c4009
		= atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
Packit 6c4009
						       newval, oldval);
Packit 6c4009
Packit 6c4009
	      if (newval != oldval)
Packit 6c4009
		{
Packit 6c4009
		  oldval = newval;
Packit 6c4009
		  goto again;
Packit 6c4009
		}
Packit 6c4009
Packit 6c4009
	      /* We got the mutex.  */
Packit 6c4009
	      mutex->__data.__count = 1;
Packit 6c4009
	      /* But it is inconsistent unless marked otherwise.  */
Packit 6c4009
	      mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
Packit 6c4009
Packit Bot cfd2ea
	      /* We must not enqueue the mutex before we have acquired it.
Packit Bot cfd2ea
		 Also see comments at ENQUEUE_MUTEX.  */
Packit Bot cfd2ea
	      __asm ("" ::: "memory");
Packit 6c4009
	      ENQUEUE_MUTEX (mutex);
Packit Bot cfd2ea
	      /* We need to clear op_pending after we enqueue the mutex.  */
Packit Bot cfd2ea
	      __asm ("" ::: "memory");
Packit 6c4009
	      THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
Packit 6c4009
Packit 6c4009
	      /* Note that we deliberately exist here.  If we fall
Packit 6c4009
		 through to the end of the function __nusers would be
Packit 6c4009
		 incremented which is not correct because the old
Packit 6c4009
		 owner has to be discounted.  */
Packit 6c4009
	      return EOWNERDEAD;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* Check whether we already hold the mutex.  */
Packit 6c4009
	  if (__glibc_unlikely ((oldval & FUTEX_TID_MASK) == id))
Packit 6c4009
	    {
Packit 6c4009
	      int kind = PTHREAD_MUTEX_TYPE (mutex);
Packit 6c4009
	      if (kind == PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP)
Packit 6c4009
		{
Packit Bot cfd2ea
		  /* We do not need to ensure ordering wrt another memory
Packit Bot cfd2ea
		     access.  Also see comments at ENQUEUE_MUTEX. */
Packit 6c4009
		  THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
Packit 6c4009
				 NULL);
Packit 6c4009
		  return EDEADLK;
Packit 6c4009
		}
Packit 6c4009
Packit 6c4009
	      if (kind == PTHREAD_MUTEX_ROBUST_RECURSIVE_NP)
Packit 6c4009
		{
Packit Bot cfd2ea
		  /* We do not need to ensure ordering wrt another memory
Packit Bot cfd2ea
		     access.  */
Packit 6c4009
		  THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
Packit 6c4009
				 NULL);
Packit 6c4009
Packit 6c4009
		  /* Just bump the counter.  */
Packit 6c4009
		  if (__glibc_unlikely (mutex->__data.__count + 1 == 0))
Packit 6c4009
		    /* Overflow of the counter.  */
Packit 6c4009
		    return EAGAIN;
Packit 6c4009
Packit 6c4009
		  ++mutex->__data.__count;
Packit 6c4009
Packit 6c4009
		  return 0;
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  oldval = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
Packit 6c4009
							id, 0);
Packit 6c4009
	  if (oldval != 0 && (oldval & FUTEX_OWNER_DIED) == 0)
Packit 6c4009
	    {
Packit Bot cfd2ea
	      /* We haven't acquired the lock as it is already acquired by
Packit Bot cfd2ea
		 another owner.  We do not need to ensure ordering wrt another
Packit Bot cfd2ea
		 memory access.  */
Packit 6c4009
	      THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
Packit 6c4009
Packit 6c4009
	      return EBUSY;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  if (__builtin_expect (mutex->__data.__owner
Packit 6c4009
				== PTHREAD_MUTEX_NOTRECOVERABLE, 0))
Packit 6c4009
	    {
Packit 6c4009
	      /* This mutex is now not recoverable.  */
Packit 6c4009
	      mutex->__data.__count = 0;
Packit 6c4009
	      if (oldval == id)
Packit 6c4009
		lll_unlock (mutex->__data.__lock,
Packit 6c4009
			    PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
Packit Bot cfd2ea
	      /* FIXME This violates the mutex destruction requirements.  See
Packit Bot cfd2ea
		 __pthread_mutex_unlock_full.  */
Packit 6c4009
	      THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
Packit 6c4009
	      return ENOTRECOVERABLE;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
      while ((oldval & FUTEX_OWNER_DIED) != 0);
Packit 6c4009
Packit Bot cfd2ea
      /* We must not enqueue the mutex before we have acquired it.
Packit Bot cfd2ea
	 Also see comments at ENQUEUE_MUTEX.  */
Packit Bot cfd2ea
      __asm ("" ::: "memory");
Packit 6c4009
      ENQUEUE_MUTEX (mutex);
Packit Bot cfd2ea
      /* We need to clear op_pending after we enqueue the mutex.  */
Packit Bot cfd2ea
      __asm ("" ::: "memory");
Packit 6c4009
      THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
Packit 6c4009
Packit 6c4009
      mutex->__data.__owner = id;
Packit 6c4009
      ++mutex->__data.__nusers;
Packit 6c4009
      mutex->__data.__count = 1;
Packit 6c4009
Packit 6c4009
      return 0;
Packit 6c4009
Packit 6c4009
    /* The PI support requires the Linux futex system call.  If that's not
Packit 6c4009
       available, pthread_mutex_init should never have allowed the type to
Packit 6c4009
       be set.  So it will get the default case for an invalid type.  */
Packit 6c4009
#ifdef __NR_futex
Packit 6c4009
    case PTHREAD_MUTEX_PI_RECURSIVE_NP:
Packit 6c4009
    case PTHREAD_MUTEX_PI_ERRORCHECK_NP:
Packit 6c4009
    case PTHREAD_MUTEX_PI_NORMAL_NP:
Packit 6c4009
    case PTHREAD_MUTEX_PI_ADAPTIVE_NP:
Packit 6c4009
    case PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP:
Packit 6c4009
    case PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP:
Packit 6c4009
    case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP:
Packit 6c4009
    case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP:
Packit 6c4009
      {
Packit Bot 45699f
	int kind, robust;
Packit Bot 45699f
	{
Packit Bot 45699f
	  /* See concurrency notes regarding __kind in struct __pthread_mutex_s
Packit Bot 45699f
	     in sysdeps/nptl/bits/thread-shared-types.h.  */
Packit Bot 45699f
	  int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind));
Packit Bot 45699f
	  kind = mutex_kind & PTHREAD_MUTEX_KIND_MASK_NP;
Packit Bot 45699f
	  robust = mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
Packit Bot 45699f
	}
Packit 6c4009
Packit 6c4009
	if (robust)
Packit Bot cfd2ea
	  {
Packit Bot cfd2ea
	    /* Note: robust PI futexes are signaled by setting bit 0.  */
Packit Bot cfd2ea
	    THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
Packit Bot cfd2ea
			   (void *) (((uintptr_t) &mutex->__data.__list.__next)
Packit Bot cfd2ea
				     | 1));
Packit Bot cfd2ea
	    /* We need to set op_pending before starting the operation.  Also
Packit Bot cfd2ea
	       see comments at ENQUEUE_MUTEX.  */
Packit Bot cfd2ea
	    __asm ("" ::: "memory");
Packit Bot cfd2ea
	  }
Packit 6c4009
Packit 6c4009
	oldval = mutex->__data.__lock;
Packit 6c4009
Packit 6c4009
	/* Check whether we already hold the mutex.  */
Packit 6c4009
	if (__glibc_unlikely ((oldval & FUTEX_TID_MASK) == id))
Packit 6c4009
	  {
Packit 6c4009
	    if (kind == PTHREAD_MUTEX_ERRORCHECK_NP)
Packit 6c4009
	      {
Packit Bot cfd2ea
		/* We do not need to ensure ordering wrt another memory
Packit Bot cfd2ea
		   access.  */
Packit 6c4009
		THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
Packit 6c4009
		return EDEADLK;
Packit 6c4009
	      }
Packit 6c4009
Packit 6c4009
	    if (kind == PTHREAD_MUTEX_RECURSIVE_NP)
Packit 6c4009
	      {
Packit Bot cfd2ea
		/* We do not need to ensure ordering wrt another memory
Packit Bot cfd2ea
		   access.  */
Packit 6c4009
		THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
Packit 6c4009
Packit 6c4009
		/* Just bump the counter.  */
Packit 6c4009
		if (__glibc_unlikely (mutex->__data.__count + 1 == 0))
Packit 6c4009
		  /* Overflow of the counter.  */
Packit 6c4009
		  return EAGAIN;
Packit 6c4009
Packit 6c4009
		++mutex->__data.__count;
Packit 6c4009
Packit 6c4009
		return 0;
Packit 6c4009
	      }
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	oldval
Packit 6c4009
	  = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
Packit 6c4009
						 id, 0);
Packit 6c4009
Packit 6c4009
	if (oldval != 0)
Packit 6c4009
	  {
Packit 6c4009
	    if ((oldval & FUTEX_OWNER_DIED) == 0)
Packit 6c4009
	      {
Packit Bot cfd2ea
		/* We haven't acquired the lock as it is already acquired by
Packit Bot cfd2ea
		   another owner.  We do not need to ensure ordering wrt another
Packit Bot cfd2ea
		   memory access.  */
Packit 6c4009
		THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
Packit 6c4009
Packit 6c4009
		return EBUSY;
Packit 6c4009
	      }
Packit 6c4009
Packit 6c4009
	    assert (robust);
Packit 6c4009
Packit 6c4009
	    /* The mutex owner died.  The kernel will now take care of
Packit 6c4009
	       everything.  */
Packit 6c4009
	    int private = (robust
Packit 6c4009
			   ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex)
Packit 6c4009
			   : PTHREAD_MUTEX_PSHARED (mutex));
Packit 6c4009
	    INTERNAL_SYSCALL_DECL (__err);
Packit 6c4009
	    int e = INTERNAL_SYSCALL (futex, __err, 4, &mutex->__data.__lock,
Packit 6c4009
				      __lll_private_flag (FUTEX_TRYLOCK_PI,
Packit 6c4009
							  private), 0, 0);
Packit 6c4009
Packit 6c4009
	    if (INTERNAL_SYSCALL_ERROR_P (e, __err)
Packit 6c4009
		&& INTERNAL_SYSCALL_ERRNO (e, __err) == EWOULDBLOCK)
Packit 6c4009
	      {
Packit Bot cfd2ea
		/* The kernel has not yet finished the mutex owner death.
Packit Bot cfd2ea
		   We do not need to ensure ordering wrt another memory
Packit Bot cfd2ea
		   access.  */
Packit 6c4009
		THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
Packit 6c4009
Packit 6c4009
		return EBUSY;
Packit 6c4009
	      }
Packit 6c4009
Packit 6c4009
	    oldval = mutex->__data.__lock;
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	if (__glibc_unlikely (oldval & FUTEX_OWNER_DIED))
Packit 6c4009
	  {
Packit 6c4009
	    atomic_and (&mutex->__data.__lock, ~FUTEX_OWNER_DIED);
Packit 6c4009
Packit 6c4009
	    /* We got the mutex.  */
Packit 6c4009
	    mutex->__data.__count = 1;
Packit 6c4009
	    /* But it is inconsistent unless marked otherwise.  */
Packit 6c4009
	    mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
Packit 6c4009
Packit Bot cfd2ea
	    /* We must not enqueue the mutex before we have acquired it.
Packit Bot cfd2ea
	       Also see comments at ENQUEUE_MUTEX.  */
Packit Bot cfd2ea
	    __asm ("" ::: "memory");
Packit 6c4009
	    ENQUEUE_MUTEX (mutex);
Packit Bot cfd2ea
	    /* We need to clear op_pending after we enqueue the mutex.  */
Packit Bot cfd2ea
	    __asm ("" ::: "memory");
Packit 6c4009
	    THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
Packit 6c4009
Packit 6c4009
	    /* Note that we deliberately exit here.  If we fall
Packit 6c4009
	       through to the end of the function __nusers would be
Packit 6c4009
	       incremented which is not correct because the old owner
Packit 6c4009
	       has to be discounted.  */
Packit 6c4009
	    return EOWNERDEAD;
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	if (robust
Packit 6c4009
	    && __builtin_expect (mutex->__data.__owner
Packit 6c4009
				 == PTHREAD_MUTEX_NOTRECOVERABLE, 0))
Packit 6c4009
	  {
Packit 6c4009
	    /* This mutex is now not recoverable.  */
Packit 6c4009
	    mutex->__data.__count = 0;
Packit 6c4009
Packit 6c4009
	    INTERNAL_SYSCALL_DECL (__err);
Packit 6c4009
	    INTERNAL_SYSCALL (futex, __err, 4, &mutex->__data.__lock,
Packit 6c4009
			      __lll_private_flag (FUTEX_UNLOCK_PI,
Packit 6c4009
						  PTHREAD_ROBUST_MUTEX_PSHARED (mutex)),
Packit 6c4009
			      0, 0);
Packit 6c4009
Packit Bot cfd2ea
	    /* To the kernel, this will be visible after the kernel has
Packit Bot cfd2ea
	       acquired the mutex in the syscall.  */
Packit 6c4009
	    THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
Packit 6c4009
	    return ENOTRECOVERABLE;
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	if (robust)
Packit 6c4009
	  {
Packit Bot cfd2ea
	    /* We must not enqueue the mutex before we have acquired it.
Packit Bot cfd2ea
	       Also see comments at ENQUEUE_MUTEX.  */
Packit Bot cfd2ea
	    __asm ("" ::: "memory");
Packit 6c4009
	    ENQUEUE_MUTEX_PI (mutex);
Packit Bot cfd2ea
	    /* We need to clear op_pending after we enqueue the mutex.  */
Packit Bot cfd2ea
	    __asm ("" ::: "memory");
Packit 6c4009
	    THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	mutex->__data.__owner = id;
Packit 6c4009
	++mutex->__data.__nusers;
Packit 6c4009
	mutex->__data.__count = 1;
Packit 6c4009
Packit 6c4009
	return 0;
Packit 6c4009
      }
Packit 6c4009
#endif  /* __NR_futex.  */
Packit 6c4009
Packit 6c4009
    case PTHREAD_MUTEX_PP_RECURSIVE_NP:
Packit 6c4009
    case PTHREAD_MUTEX_PP_ERRORCHECK_NP:
Packit 6c4009
    case PTHREAD_MUTEX_PP_NORMAL_NP:
Packit 6c4009
    case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
Packit 6c4009
      {
Packit Bot 45699f
	/* See concurrency notes regarding __kind in struct __pthread_mutex_s
Packit Bot 45699f
	   in sysdeps/nptl/bits/thread-shared-types.h.  */
Packit Bot 45699f
	int kind = atomic_load_relaxed (&(mutex->__data.__kind))
Packit Bot 45699f
	  & PTHREAD_MUTEX_KIND_MASK_NP;
Packit 6c4009
Packit 6c4009
	oldval = mutex->__data.__lock;
Packit 6c4009
Packit 6c4009
	/* Check whether we already hold the mutex.  */
Packit 6c4009
	if (mutex->__data.__owner == id)
Packit 6c4009
	  {
Packit 6c4009
	    if (kind == PTHREAD_MUTEX_ERRORCHECK_NP)
Packit 6c4009
	      return EDEADLK;
Packit 6c4009
Packit 6c4009
	    if (kind == PTHREAD_MUTEX_RECURSIVE_NP)
Packit 6c4009
	      {
Packit 6c4009
		/* Just bump the counter.  */
Packit 6c4009
		if (__glibc_unlikely (mutex->__data.__count + 1 == 0))
Packit 6c4009
		  /* Overflow of the counter.  */
Packit 6c4009
		  return EAGAIN;
Packit 6c4009
Packit 6c4009
		++mutex->__data.__count;
Packit 6c4009
Packit 6c4009
		return 0;
Packit 6c4009
	      }
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	int oldprio = -1, ceilval;
Packit 6c4009
	do
Packit 6c4009
	  {
Packit 6c4009
	    int ceiling = (oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK)
Packit 6c4009
			  >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
Packit 6c4009
Packit 6c4009
	    if (__pthread_current_priority () > ceiling)
Packit 6c4009
	      {
Packit 6c4009
		if (oldprio != -1)
Packit 6c4009
		  __pthread_tpp_change_priority (oldprio, -1);
Packit 6c4009
		return EINVAL;
Packit 6c4009
	      }
Packit 6c4009
Packit 6c4009
	    int retval = __pthread_tpp_change_priority (oldprio, ceiling);
Packit 6c4009
	    if (retval)
Packit 6c4009
	      return retval;
Packit 6c4009
Packit 6c4009
	    ceilval = ceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
Packit 6c4009
	    oldprio = ceiling;
Packit 6c4009
Packit 6c4009
	    oldval
Packit 6c4009
	      = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
Packit 6c4009
						     ceilval | 1, ceilval);
Packit 6c4009
Packit 6c4009
	    if (oldval == ceilval)
Packit 6c4009
	      break;
Packit 6c4009
	  }
Packit 6c4009
	while ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval);
Packit 6c4009
Packit 6c4009
	if (oldval != ceilval)
Packit 6c4009
	  {
Packit 6c4009
	    __pthread_tpp_change_priority (oldprio, -1);
Packit 6c4009
	    break;
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	assert (mutex->__data.__owner == 0);
Packit 6c4009
	/* Record the ownership.  */
Packit 6c4009
	mutex->__data.__owner = id;
Packit 6c4009
	++mutex->__data.__nusers;
Packit 6c4009
	mutex->__data.__count = 1;
Packit 6c4009
Packit 6c4009
	return 0;
Packit 6c4009
      }
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    default:
Packit 6c4009
      /* Correct code cannot set any other type.  */
Packit 6c4009
      return EINVAL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return EBUSY;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#ifndef __pthread_mutex_trylock
Packit 6c4009
#ifndef pthread_mutex_trylock
Packit 6c4009
weak_alias (__pthread_mutex_trylock, pthread_mutex_trylock)
Packit 6c4009
hidden_def (__pthread_mutex_trylock)
Packit 6c4009
#endif
Packit 6c4009
#endif