pthread_mutex_timedlock.c raw

   1  #include "pthread_impl.h"
   2  
   3  #define IS32BIT(x) !((x)+0x80000000ULL>>32)
   4  #define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63))
   5  
   6  static int __futex4(volatile void *addr, int op, int val, const struct timespec *to)
   7  {
   8  #ifdef SYS_futex_time64
   9  	time_t s = to ? to->tv_sec : 0;
  10  	long ns = to ? to->tv_nsec : 0;
  11  	int r = -ENOSYS;
  12  	if (SYS_futex == SYS_futex_time64 || !IS32BIT(s))
  13  		r = __syscall(SYS_futex_time64, addr, op, val,
  14  			to ? ((long long[]){s, ns}) : 0);
  15  	if (SYS_futex == SYS_futex_time64 || r!=-ENOSYS) return r;
  16  	to = to ? (void *)(long[]){CLAMP(s), ns} : 0;
  17  #endif
  18  	return __syscall(SYS_futex, addr, op, val, to);
  19  }
  20  
  21  static int pthread_mutex_timedlock_pi(pthread_mutex_t *restrict m, const struct timespec *restrict at)
  22  {
  23  	int type = m->_m_type;
  24  	int priv = (type & 128) ^ 128;
  25  	pthread_t self = __pthread_self();
  26  	int e;
  27  
  28  	if (!priv) self->robust_list.pending = &m->_m_next;
  29  
  30  	do e = -__futex4(&m->_m_lock, FUTEX_LOCK_PI|priv, 0, at);
  31  	while (e==EINTR);
  32  	if (e) self->robust_list.pending = 0;
  33  
  34  	switch (e) {
  35  	case 0:
  36  		/* Catch spurious success for non-robust mutexes. */
  37  		if (!(type&4) && ((m->_m_lock & 0x40000000) || m->_m_waiters)) {
  38  			a_store(&m->_m_waiters, -1);
  39  			__syscall(SYS_futex, &m->_m_lock, FUTEX_UNLOCK_PI|priv);
  40  			self->robust_list.pending = 0;
  41  			break;
  42  		}
  43  		/* Signal to trylock that we already have the lock. */
  44  		m->_m_count = -1;
  45  		return __pthread_mutex_trylock(m);
  46  	case ETIMEDOUT:
  47  		return e;
  48  	case EDEADLK:
  49  		if ((type&3) == PTHREAD_MUTEX_ERRORCHECK) return e;
  50  	}
  51  	do e = __timedwait(&(int){0}, 0, CLOCK_REALTIME, at, 1);
  52  	while (e != ETIMEDOUT);
  53  	return e;
  54  }
  55  
  56  int __pthread_mutex_timedlock(pthread_mutex_t *restrict m, const struct timespec *restrict at)
  57  {
  58  	if ((m->_m_type&15) == PTHREAD_MUTEX_NORMAL
  59  	    && !a_cas(&m->_m_lock, 0, EBUSY))
  60  		return 0;
  61  
  62  	int type = m->_m_type;
  63  	int r, t, priv = (type & 128) ^ 128;
  64  
  65  	r = __pthread_mutex_trylock(m);
  66  	if (r != EBUSY) return r;
  67  
  68  	if (type&8) return pthread_mutex_timedlock_pi(m, at);
  69  	
  70  	int spins = 100;
  71  	while (spins-- && m->_m_lock && !m->_m_waiters) a_spin();
  72  
  73  	while ((r=__pthread_mutex_trylock(m)) == EBUSY) {
  74  		r = m->_m_lock;
  75  		int own = r & 0x3fffffff;
  76  		if (!own && (!r || (type&4)))
  77  			continue;
  78  		if ((type&3) == PTHREAD_MUTEX_ERRORCHECK
  79  		    && own == __pthread_self()->tid)
  80  			return EDEADLK;
  81  
  82  		a_inc(&m->_m_waiters);
  83  		t = r | 0x80000000;
  84  		a_cas(&m->_m_lock, r, t);
  85  		r = __timedwait(&m->_m_lock, t, CLOCK_REALTIME, at, priv);
  86  		a_dec(&m->_m_waiters);
  87  		if (r && r != EINTR) break;
  88  	}
  89  	return r;
  90  }
  91  
  92  weak_alias(__pthread_mutex_timedlock, pthread_mutex_timedlock);
  93