(root)/
glibc-2.38/
nptl/
pthread_mutex_setprioceiling.c
       1  /* Set current priority ceiling of pthread_mutex_t.
       2     Copyright (C) 2006-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <stdbool.h>
      20  #include <errno.h>
      21  #include <pthreadP.h>
      22  #include <atomic.h>
      23  #include <futex-internal.h>
      24  #include <shlib-compat.h>
      25  
      26  int
      27  __pthread_mutex_setprioceiling (pthread_mutex_t *mutex, int prioceiling,
      28  				int *old_ceiling)
      29  {
      30    /* See concurrency notes regarding __kind in struct __pthread_mutex_s
      31       in sysdeps/nptl/bits/thread-shared-types.h.  */
      32    if ((atomic_load_relaxed (&(mutex->__data.__kind))
      33         & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0)
      34      return EINVAL;
      35  
      36    /* See __init_sched_fifo_prio.  */
      37    if (atomic_load_relaxed (&__sched_fifo_min_prio) == -1
      38        || atomic_load_relaxed (&__sched_fifo_max_prio) == -1)
      39      __init_sched_fifo_prio ();
      40  
      41    if (__glibc_unlikely (prioceiling
      42  			< atomic_load_relaxed (&__sched_fifo_min_prio))
      43        || __glibc_unlikely (prioceiling
      44  			   > atomic_load_relaxed (&__sched_fifo_max_prio))
      45        || __glibc_unlikely ((prioceiling
      46  			    & (PTHREAD_MUTEXATTR_PRIO_CEILING_MASK
      47  			       >> PTHREAD_MUTEXATTR_PRIO_CEILING_SHIFT))
      48  			   != prioceiling))
      49      return EINVAL;
      50  
      51    /* Check whether we already hold the mutex.  */
      52    bool locked = false;
      53    int kind = PTHREAD_MUTEX_TYPE (mutex);
      54    if (mutex->__data.__owner == THREAD_GETMEM (THREAD_SELF, tid))
      55      {
      56        if (kind == PTHREAD_MUTEX_PP_ERRORCHECK_NP)
      57  	return EDEADLK;
      58  
      59        if (kind == PTHREAD_MUTEX_PP_RECURSIVE_NP)
      60  	locked = true;
      61      }
      62  
      63    int oldval = mutex->__data.__lock;
      64    if (! locked)
      65      do
      66        {
      67  	/* Need to lock the mutex, but without obeying the priority
      68  	   protect protocol.  */
      69  	int ceilval = (oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK);
      70  
      71  	oldval = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
      72  						      ceilval | 1, ceilval);
      73  	if (oldval == ceilval)
      74  	  break;
      75  
      76  	do
      77  	  {
      78  	    oldval
      79  	      = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
      80  						     ceilval | 2,
      81  						     ceilval | 1);
      82  
      83  	    if ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval)
      84  	      break;
      85  
      86  	    if (oldval != ceilval)
      87  	      futex_wait ((unsigned int *) &mutex->__data.__lock, ceilval | 2,
      88  			  PTHREAD_MUTEX_PSHARED (mutex));
      89  	  }
      90  	while (atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
      91  						    ceilval | 2, ceilval)
      92  	       != ceilval);
      93  
      94  	if ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval)
      95  	  continue;
      96        }
      97      while (0);
      98  
      99    int oldprio = (oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK)
     100  		>> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
     101    if (locked)
     102      {
     103        int ret = __pthread_tpp_change_priority (oldprio, prioceiling);
     104        if (ret)
     105  	return ret;
     106      }
     107  
     108    if (old_ceiling != NULL)
     109      *old_ceiling = oldprio;
     110  
     111    int newlock = 0;
     112    if (locked)
     113      newlock = (mutex->__data.__lock & ~PTHREAD_MUTEX_PRIO_CEILING_MASK);
     114    mutex->__data.__lock = newlock
     115  			 | (prioceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT);
     116    atomic_full_barrier ();
     117  
     118    futex_wake ((unsigned int *)&mutex->__data.__lock, INT_MAX,
     119  	      PTHREAD_MUTEX_PSHARED (mutex));
     120  
     121    return 0;
     122  }
     123  versioned_symbol (libc, __pthread_mutex_setprioceiling,
     124  		  pthread_mutex_setprioceiling, GLIBC_2_34);
     125  
     126  #if OTHER_SHLIB_COMPAT (libpthread, GLIBC_2_4, GLIBC_2_34)
     127  compat_symbol (libpthread, __pthread_mutex_setprioceiling,
     128                 pthread_mutex_setprioceiling, GLIBC_2_4);
     129  #endif