(root)/
glibc-2.38/
nptl/
pthread_mutex_timedlock.c
       1  /* Copyright (C) 2002-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <assert.h>
      19  #include <errno.h>
      20  #include <time.h>
      21  #include <sys/param.h>
      22  #include <sys/time.h>
      23  #include "pthreadP.h"
      24  #include <atomic.h>
      25  #include <lowlevellock.h>
      26  #include <not-cancel.h>
      27  #include <futex-internal.h>
      28  
      29  #include <stap-probe.h>
      30  
      31  int
      32  __pthread_mutex_clocklock_common (pthread_mutex_t *mutex,
      33  				  clockid_t clockid,
      34  				  const struct __timespec64 *abstime)
      35  {
      36    int oldval;
      37    pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
      38    int result = 0;
      39  
      40    /* We must not check ABSTIME here.  If the thread does not block
      41       abstime must not be checked for a valid value.  */
      42  
      43    /* See concurrency notes regarding mutex type which is loaded from __kind
      44       in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h.  */
      45    switch (__builtin_expect (PTHREAD_MUTEX_TYPE_ELISION (mutex),
      46  			    PTHREAD_MUTEX_TIMED_NP))
      47      {
      48        /* Recursive mutex.  */
      49      case PTHREAD_MUTEX_RECURSIVE_NP|PTHREAD_MUTEX_ELISION_NP:
      50      case PTHREAD_MUTEX_RECURSIVE_NP:
      51        /* Check whether we already hold the mutex.  */
      52        if (mutex->__data.__owner == id)
      53  	{
      54  	  /* Just bump the counter.  */
      55  	  if (__glibc_unlikely (mutex->__data.__count + 1 == 0))
      56  	    /* Overflow of the counter.  */
      57  	    return EAGAIN;
      58  
      59  	  ++mutex->__data.__count;
      60  
      61  	  goto out;
      62  	}
      63  
      64        /* We have to get the mutex.  */
      65        result = __futex_clocklock64 (&mutex->__data.__lock, clockid, abstime,
      66                                      PTHREAD_MUTEX_PSHARED (mutex));
      67  
      68        if (result != 0)
      69  	goto out;
      70  
      71        /* Only locked once so far.  */
      72        mutex->__data.__count = 1;
      73        break;
      74  
      75        /* Error checking mutex.  */
      76      case PTHREAD_MUTEX_ERRORCHECK_NP:
      77        /* Check whether we already hold the mutex.  */
      78        if (__glibc_unlikely (mutex->__data.__owner == id))
      79  	return EDEADLK;
      80  
      81        /* Don't do lock elision on an error checking mutex.  */
      82        goto simple;
      83  
      84      case PTHREAD_MUTEX_TIMED_NP:
      85        FORCE_ELISION (mutex, goto elision);
      86      simple:
      87        /* Normal mutex.  */
      88        result = __futex_clocklock64 (&mutex->__data.__lock, clockid, abstime,
      89                                      PTHREAD_MUTEX_PSHARED (mutex));
      90        break;
      91  
      92      case PTHREAD_MUTEX_TIMED_ELISION_NP:
      93      elision: __attribute__((unused))
      94        /* Don't record ownership */
      95        return lll_clocklock_elision (mutex->__data.__lock,
      96  				    mutex->__data.__spins,
      97  				    clockid, abstime,
      98  				    PTHREAD_MUTEX_PSHARED (mutex));
      99  
     100  
     101      case PTHREAD_MUTEX_ADAPTIVE_NP:
     102        if (lll_trylock (mutex->__data.__lock) != 0)
     103  	{
     104  	  int cnt = 0;
     105  	  int max_cnt = MIN (max_adaptive_count (),
     106  			     mutex->__data.__spins * 2 + 10);
     107  	  do
     108  	    {
     109  	      if (cnt++ >= max_cnt)
     110  		{
     111  		  result = __futex_clocklock64 (&mutex->__data.__lock,
     112  		                                clockid, abstime,
     113  		                                PTHREAD_MUTEX_PSHARED (mutex));
     114  		  break;
     115  		}
     116  	      atomic_spin_nop ();
     117  	    }
     118  	  while (lll_trylock (mutex->__data.__lock) != 0);
     119  
     120  	  mutex->__data.__spins += (cnt - mutex->__data.__spins) / 8;
     121  	}
     122        break;
     123  
     124      case PTHREAD_MUTEX_ROBUST_RECURSIVE_NP:
     125      case PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP:
     126      case PTHREAD_MUTEX_ROBUST_NORMAL_NP:
     127      case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP:
     128        THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
     129  		     &mutex->__data.__list.__next);
     130        /* We need to set op_pending before starting the operation.  Also
     131  	 see comments at ENQUEUE_MUTEX.  */
     132        __asm ("" ::: "memory");
     133  
     134        oldval = mutex->__data.__lock;
     135        /* This is set to FUTEX_WAITERS iff we might have shared the
     136  	 FUTEX_WAITERS flag with other threads, and therefore need to keep it
     137  	 set to avoid lost wake-ups.  We have the same requirement in the
     138  	 simple mutex algorithm.  */
     139        unsigned int assume_other_futex_waiters = 0;
     140        while (1)
     141  	{
     142  	  /* Try to acquire the lock through a CAS from 0 (not acquired) to
     143  	     our TID | assume_other_futex_waiters.  */
     144  	  if (__glibc_likely (oldval == 0))
     145  	    {
     146  	      oldval
     147  	        = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
     148  	            id | assume_other_futex_waiters, 0);
     149  	      if (__glibc_likely (oldval == 0))
     150  		break;
     151  	    }
     152  
     153  	  if ((oldval & FUTEX_OWNER_DIED) != 0)
     154  	    {
     155  	      /* The previous owner died.  Try locking the mutex.  */
     156  	      int newval = id | (oldval & FUTEX_WAITERS)
     157  		  | assume_other_futex_waiters;
     158  
     159  	      newval
     160  		= atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
     161  						       newval, oldval);
     162  	      if (newval != oldval)
     163  		{
     164  		  oldval = newval;
     165  		  continue;
     166  		}
     167  
     168  	      /* We got the mutex.  */
     169  	      mutex->__data.__count = 1;
     170  	      /* But it is inconsistent unless marked otherwise.  */
     171  	      mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
     172  
     173  	      /* We must not enqueue the mutex before we have acquired it.
     174  		 Also see comments at ENQUEUE_MUTEX.  */
     175  	      __asm ("" ::: "memory");
     176  	      ENQUEUE_MUTEX (mutex);
     177  	      /* We need to clear op_pending after we enqueue the mutex.  */
     178  	      __asm ("" ::: "memory");
     179  	      THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
     180  
     181  	      /* Note that we deliberately exit here.  If we fall
     182  		 through to the end of the function __nusers would be
     183  		 incremented which is not correct because the old
     184  		 owner has to be discounted.  */
     185  	      return EOWNERDEAD;
     186  	    }
     187  
     188  	  /* Check whether we already hold the mutex.  */
     189  	  if (__glibc_unlikely ((oldval & FUTEX_TID_MASK) == id))
     190  	    {
     191  	      int kind = PTHREAD_MUTEX_TYPE (mutex);
     192  	      if (kind == PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP)
     193  		{
     194  		  /* We do not need to ensure ordering wrt another memory
     195  		     access.  Also see comments at ENQUEUE_MUTEX. */
     196  		  THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
     197  				 NULL);
     198  		  return EDEADLK;
     199  		}
     200  
     201  	      if (kind == PTHREAD_MUTEX_ROBUST_RECURSIVE_NP)
     202  		{
     203  		  /* We do not need to ensure ordering wrt another memory
     204  		     access.  */
     205  		  THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
     206  				 NULL);
     207  
     208  		  /* Just bump the counter.  */
     209  		  if (__glibc_unlikely (mutex->__data.__count + 1 == 0))
     210  		    /* Overflow of the counter.  */
     211  		    return EAGAIN;
     212  
     213  		  ++mutex->__data.__count;
     214  
     215  		  LIBC_PROBE (mutex_timedlock_acquired, 1, mutex);
     216  
     217  		  return 0;
     218  		}
     219  	    }
     220  
     221  	  /* We are about to block; check whether the timeout is invalid.  */
     222  	  if (! valid_nanoseconds (abstime->tv_nsec))
     223  	    return EINVAL;
     224  	  /* Work around the fact that the kernel rejects negative timeout
     225  	     values despite them being valid.  */
     226  	  if (__glibc_unlikely (abstime->tv_sec < 0))
     227  	    return ETIMEDOUT;
     228  
     229  	  /* We cannot acquire the mutex nor has its owner died.  Thus, try
     230  	     to block using futexes.  Set FUTEX_WAITERS if necessary so that
     231  	     other threads are aware that there are potentially threads
     232  	     blocked on the futex.  Restart if oldval changed in the
     233  	     meantime.  */
     234  	  if ((oldval & FUTEX_WAITERS) == 0)
     235  	    {
     236  	      int val = atomic_compare_and_exchange_val_acq
     237  		(&mutex->__data.__lock, oldval | FUTEX_WAITERS, oldval);
     238  	      if (val != oldval)
     239  		{
     240  		  oldval = val;
     241  		  continue;
     242  		}
     243  	      oldval |= FUTEX_WAITERS;
     244  	    }
     245  
     246  	  /* It is now possible that we share the FUTEX_WAITERS flag with
     247  	     another thread; therefore, update assume_other_futex_waiters so
     248  	     that we do not forget about this when handling other cases
     249  	     above and thus do not cause lost wake-ups.  */
     250  	  assume_other_futex_waiters |= FUTEX_WAITERS;
     251  
     252  	  /* Block using the futex.  */
     253  	  int err = __futex_abstimed_wait64 (
     254  	      (unsigned int *) &mutex->__data.__lock,
     255  	      oldval, clockid, abstime,
     256  	      PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
     257  	  /* The futex call timed out.  */
     258  	  if (err == ETIMEDOUT || err == EOVERFLOW)
     259  	    return err;
     260  	  /* Reload current lock value.  */
     261  	  oldval = mutex->__data.__lock;
     262  	}
     263  
     264        /* We have acquired the mutex; check if it is still consistent.  */
     265        if (__builtin_expect (mutex->__data.__owner
     266  			    == PTHREAD_MUTEX_NOTRECOVERABLE, 0))
     267  	{
     268  	  /* This mutex is now not recoverable.  */
     269  	  mutex->__data.__count = 0;
     270  	  int private = PTHREAD_ROBUST_MUTEX_PSHARED (mutex);
     271  	  lll_unlock (mutex->__data.__lock, private);
     272  	  /* FIXME This violates the mutex destruction requirements.  See
     273  	     __pthread_mutex_unlock_full.  */
     274  	  THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
     275  	  return ENOTRECOVERABLE;
     276  	}
     277  
     278        mutex->__data.__count = 1;
     279        /* We must not enqueue the mutex before we have acquired it.
     280  	 Also see comments at ENQUEUE_MUTEX.  */
     281        __asm ("" ::: "memory");
     282        ENQUEUE_MUTEX (mutex);
     283        /* We need to clear op_pending after we enqueue the mutex.  */
     284        __asm ("" ::: "memory");
     285        THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
     286        break;
     287  
     288      /* The PI support requires the Linux futex system call.  If that's not
     289         available, pthread_mutex_init should never have allowed the type to
     290         be set.  So it will get the default case for an invalid type.  */
     291  #ifdef __NR_futex
     292      case PTHREAD_MUTEX_PI_RECURSIVE_NP:
     293      case PTHREAD_MUTEX_PI_ERRORCHECK_NP:
     294      case PTHREAD_MUTEX_PI_NORMAL_NP:
     295      case PTHREAD_MUTEX_PI_ADAPTIVE_NP:
     296      case PTHREAD_MUTEX_PI_ROBUST_RECURSIVE_NP:
     297      case PTHREAD_MUTEX_PI_ROBUST_ERRORCHECK_NP:
     298      case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP:
     299      case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP:
     300        {
     301  	int kind, robust;
     302  	{
     303  	  /* See concurrency notes regarding __kind in struct __pthread_mutex_s
     304  	     in sysdeps/nptl/bits/thread-shared-types.h.  */
     305  	  int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind));
     306  	  kind = mutex_kind & PTHREAD_MUTEX_KIND_MASK_NP;
     307  	  robust = mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
     308  	}
     309  
     310  	if (robust)
     311  	  {
     312  	    /* Note: robust PI futexes are signaled by setting bit 0.  */
     313  	    THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
     314  			   (void *) (((uintptr_t) &mutex->__data.__list.__next)
     315  				     | 1));
     316  	    /* We need to set op_pending before starting the operation.  Also
     317  	       see comments at ENQUEUE_MUTEX.  */
     318  	    __asm ("" ::: "memory");
     319  	  }
     320  
     321  	oldval = mutex->__data.__lock;
     322  
     323  	/* Check whether we already hold the mutex.  */
     324  	if (__glibc_unlikely ((oldval & FUTEX_TID_MASK) == id))
     325  	  {
     326  	    if (kind == PTHREAD_MUTEX_ERRORCHECK_NP)
     327  	      {
     328  		/* We do not need to ensure ordering wrt another memory
     329  		   access.  */
     330  		THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
     331  		return EDEADLK;
     332  	      }
     333  
     334  	    if (kind == PTHREAD_MUTEX_RECURSIVE_NP)
     335  	      {
     336  		/* We do not need to ensure ordering wrt another memory
     337  		   access.  */
     338  		THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
     339  
     340  		/* Just bump the counter.  */
     341  		if (__glibc_unlikely (mutex->__data.__count + 1 == 0))
     342  		  /* Overflow of the counter.  */
     343  		  return EAGAIN;
     344  
     345  		++mutex->__data.__count;
     346  
     347  		LIBC_PROBE (mutex_timedlock_acquired, 1, mutex);
     348  
     349  		return 0;
     350  	      }
     351  	  }
     352  
     353  	oldval = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
     354  						      id, 0);
     355  
     356  	if (oldval != 0)
     357  	  {
     358  	    /* The mutex is locked.  The kernel will now take care of
     359  	       everything.  The timeout value must be a relative value.
     360  	       Convert it.  */
     361  	    int private = (robust
     362  			   ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex)
     363  			   : PTHREAD_MUTEX_PSHARED (mutex));
     364  	    int e = __futex_lock_pi64 (&mutex->__data.__lock, clockid, abstime,
     365  				       private);
     366  	    if (e == ETIMEDOUT)
     367  	      return ETIMEDOUT;
     368  	    else if (e == ESRCH || e == EDEADLK)
     369  	      {
     370  		assert (e != EDEADLK
     371  			|| (kind != PTHREAD_MUTEX_ERRORCHECK_NP
     372  			   && kind != PTHREAD_MUTEX_RECURSIVE_NP));
     373  		/* ESRCH can happen only for non-robust PI mutexes where
     374  		   the owner of the lock died.  */
     375  		assert (e != ESRCH || !robust);
     376  
     377  		/* Delay the thread until the timeout is reached. Then return
     378  		   ETIMEDOUT.  */
     379  		do
     380  		  e = __futex_abstimed_wait64 (&(unsigned int){0}, 0, clockid,
     381  					       abstime, private);
     382  		while (e != ETIMEDOUT);
     383  		return ETIMEDOUT;
     384  	      }
     385  	    else if (e != 0)
     386  	      return e;
     387  
     388  	    oldval = mutex->__data.__lock;
     389  
     390  	    assert (robust || (oldval & FUTEX_OWNER_DIED) == 0);
     391  	  }
     392  
     393  	if (__glibc_unlikely (oldval & FUTEX_OWNER_DIED))
     394  	  {
     395  	    atomic_fetch_and_acquire (&mutex->__data.__lock, ~FUTEX_OWNER_DIED);
     396  
     397  	    /* We got the mutex.  */
     398  	    mutex->__data.__count = 1;
     399  	    /* But it is inconsistent unless marked otherwise.  */
     400  	    mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
     401  
     402  	    /* We must not enqueue the mutex before we have acquired it.
     403  	       Also see comments at ENQUEUE_MUTEX.  */
     404  	    __asm ("" ::: "memory");
     405  	    ENQUEUE_MUTEX_PI (mutex);
     406  	    /* We need to clear op_pending after we enqueue the mutex.  */
     407  	    __asm ("" ::: "memory");
     408  	    THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
     409  
     410  	    /* Note that we deliberately exit here.  If we fall
     411  	       through to the end of the function __nusers would be
     412  	       incremented which is not correct because the old owner
     413  	       has to be discounted.  */
     414  	    return EOWNERDEAD;
     415  	  }
     416  
     417  	if (robust
     418  	    && __builtin_expect (mutex->__data.__owner
     419  				 == PTHREAD_MUTEX_NOTRECOVERABLE, 0))
     420  	  {
     421  	    /* This mutex is now not recoverable.  */
     422  	    mutex->__data.__count = 0;
     423  
     424  	    futex_unlock_pi ((unsigned int *) &mutex->__data.__lock,
     425  			     PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
     426  
     427  	    /* To the kernel, this will be visible after the kernel has
     428  	       acquired the mutex in the syscall.  */
     429  	    THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
     430  	    return ENOTRECOVERABLE;
     431  	  }
     432  
     433  	mutex->__data.__count = 1;
     434  	if (robust)
     435  	  {
     436  	    /* We must not enqueue the mutex before we have acquired it.
     437  	       Also see comments at ENQUEUE_MUTEX.  */
     438  	    __asm ("" ::: "memory");
     439  	    ENQUEUE_MUTEX_PI (mutex);
     440  	    /* We need to clear op_pending after we enqueue the mutex.  */
     441  	    __asm ("" ::: "memory");
     442  	    THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
     443  	  }
     444  	}
     445        break;
     446  #endif  /* __NR_futex.  */
     447  
     448      case PTHREAD_MUTEX_PP_RECURSIVE_NP:
     449      case PTHREAD_MUTEX_PP_ERRORCHECK_NP:
     450      case PTHREAD_MUTEX_PP_NORMAL_NP:
     451      case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
     452        {
     453  	/* See concurrency notes regarding __kind in struct __pthread_mutex_s
     454  	   in sysdeps/nptl/bits/thread-shared-types.h.  */
     455  	int kind = atomic_load_relaxed (&(mutex->__data.__kind))
     456  	  & PTHREAD_MUTEX_KIND_MASK_NP;
     457  
     458  	oldval = mutex->__data.__lock;
     459  
     460  	/* Check whether we already hold the mutex.  */
     461  	if (mutex->__data.__owner == id)
     462  	  {
     463  	    if (kind == PTHREAD_MUTEX_ERRORCHECK_NP)
     464  	      return EDEADLK;
     465  
     466  	    if (kind == PTHREAD_MUTEX_RECURSIVE_NP)
     467  	      {
     468  		/* Just bump the counter.  */
     469  		if (__glibc_unlikely (mutex->__data.__count + 1 == 0))
     470  		  /* Overflow of the counter.  */
     471  		  return EAGAIN;
     472  
     473  		++mutex->__data.__count;
     474  
     475  		LIBC_PROBE (mutex_timedlock_acquired, 1, mutex);
     476  
     477  		return 0;
     478  	      }
     479  	  }
     480  
     481  	int oldprio = -1, ceilval;
     482  	do
     483  	  {
     484  	    int ceiling = (oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK)
     485  			  >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
     486  
     487  	    if (__pthread_current_priority () > ceiling)
     488  	      {
     489  		result = EINVAL;
     490  	      failpp:
     491  		if (oldprio != -1)
     492  		  __pthread_tpp_change_priority (oldprio, -1);
     493  		return result;
     494  	      }
     495  
     496  	    result = __pthread_tpp_change_priority (oldprio, ceiling);
     497  	    if (result)
     498  	      return result;
     499  
     500  	    ceilval = ceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
     501  	    oldprio = ceiling;
     502  
     503  	    oldval
     504  	      = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
     505  						     ceilval | 1, ceilval);
     506  
     507  	    if (oldval == ceilval)
     508  	      break;
     509  
     510  	    do
     511  	      {
     512  		oldval
     513  		  = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
     514  							 ceilval | 2,
     515  							 ceilval | 1);
     516  
     517  		if ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval)
     518  		  break;
     519  
     520  		if (oldval != ceilval)
     521  		  {
     522  		    /* Reject invalid timeouts.  */
     523  		    if (! valid_nanoseconds (abstime->tv_nsec))
     524  		      {
     525  			result = EINVAL;
     526  			goto failpp;
     527  		      }
     528  
     529  		    int e = __futex_abstimed_wait64 (
     530  		      (unsigned int *) &mutex->__data.__lock, ceilval | 2,
     531  		      clockid, abstime, PTHREAD_MUTEX_PSHARED (mutex));
     532  		    if (e == ETIMEDOUT || e == EOVERFLOW)
     533  		      return e;
     534  		  }
     535  	      }
     536  	    while (atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
     537  							ceilval | 2, ceilval)
     538  		   != ceilval);
     539  	  }
     540  	while ((oldval & PTHREAD_MUTEX_PRIO_CEILING_MASK) != ceilval);
     541  
     542  	assert (mutex->__data.__owner == 0);
     543  	mutex->__data.__count = 1;
     544        }
     545        break;
     546  
     547      default:
     548        /* Correct code cannot set any other type.  */
     549        return EINVAL;
     550      }
     551  
     552    if (result == 0)
     553      {
     554        /* Record the ownership.  */
     555        mutex->__data.__owner = id;
     556        ++mutex->__data.__nusers;
     557  
     558        LIBC_PROBE (mutex_timedlock_acquired, 1, mutex);
     559      }
     560  
     561   out:
     562    return result;
     563  }
     564  
     565  int
     566  ___pthread_mutex_clocklock64 (pthread_mutex_t *mutex,
     567  			      clockid_t clockid,
     568  			      const struct __timespec64 *abstime)
     569  {
     570    if (__glibc_unlikely (!futex_abstimed_supported_clockid (clockid)))
     571      return EINVAL;
     572  
     573    LIBC_PROBE (mutex_clocklock_entry, 3, mutex, clockid, abstime);
     574    return __pthread_mutex_clocklock_common (mutex, clockid, abstime);
     575  }
     576  
     577  #if __TIMESIZE == 64
     578  strong_alias (___pthread_mutex_clocklock64, ___pthread_mutex_clocklock)
     579  #else /* __TIMESPEC64 != 64 */
     580  strong_alias (___pthread_mutex_clocklock64, __pthread_mutex_clocklock64)
     581  libc_hidden_def (__pthread_mutex_clocklock64)
     582  
     583  int
     584  ___pthread_mutex_clocklock (pthread_mutex_t *mutex,
     585  			    clockid_t clockid,
     586  			    const struct timespec *abstime)
     587  {
     588    struct __timespec64 ts64 = valid_timespec_to_timespec64 (*abstime);
     589  
     590    return ___pthread_mutex_clocklock64 (mutex, clockid, &ts64);
     591  }
     592  #endif /* __TIMESPEC64 != 64 */
     593  libc_hidden_ver (___pthread_mutex_clocklock, __pthread_mutex_clocklock)
     594  #ifndef SHARED
     595  strong_alias (___pthread_mutex_clocklock, __pthread_mutex_clocklock)
     596  #endif
     597  versioned_symbol (libc, ___pthread_mutex_clocklock,
     598  		  pthread_mutex_clocklock, GLIBC_2_34);
     599  #if OTHER_SHLIB_COMPAT (libpthread, GLIBC_2_30, GLIBC_2_34)
     600  compat_symbol (libpthread, ___pthread_mutex_clocklock,
     601  	       pthread_mutex_clocklock, GLIBC_2_30);
     602  #endif
     603  
     604  int
     605  ___pthread_mutex_timedlock64 (pthread_mutex_t *mutex,
     606  			     const struct __timespec64 *abstime)
     607  {
     608    LIBC_PROBE (mutex_timedlock_entry, 2, mutex, abstime);
     609    return __pthread_mutex_clocklock_common (mutex, CLOCK_REALTIME, abstime);
     610  }
     611  
     612  #if __TIMESIZE == 64
     613  strong_alias (___pthread_mutex_timedlock64, ___pthread_mutex_timedlock)
     614  #else /* __TIMESPEC64 != 64 */
     615  strong_alias (___pthread_mutex_timedlock64, __pthread_mutex_timedlock64);
     616  libc_hidden_def (__pthread_mutex_timedlock64)
     617  
     618  int
     619  ___pthread_mutex_timedlock (pthread_mutex_t *mutex,
     620  			   const struct timespec *abstime)
     621  {
     622    struct __timespec64 ts64 = valid_timespec_to_timespec64 (*abstime);
     623  
     624    return __pthread_mutex_timedlock64 (mutex, &ts64);
     625  }
     626  #endif /* __TIMESPEC64 != 64 */
     627  versioned_symbol (libc, ___pthread_mutex_timedlock,
     628  		  pthread_mutex_timedlock, GLIBC_2_34);
     629  libc_hidden_ver (___pthread_mutex_timedlock, __pthread_mutex_timedlock)
     630  #ifndef SHARED
     631  strong_alias (___pthread_mutex_timedlock, __pthread_mutex_timedlock)
     632  #endif
     633  
     634  #if OTHER_SHLIB_COMPAT (libpthread, GLIBC_2_2, GLIBC_2_34)
     635  compat_symbol (libpthread, ___pthread_mutex_timedlock,
     636  	       pthread_mutex_timedlock, GLIBC_2_2);
     637  #endif