refrain from spinning on locks when there is already a waiter
authorRich Felker <dalias@aerifal.cx>
Tue, 26 Aug 2014 00:24:07 +0000 (20:24 -0400)
committerRich Felker <dalias@aerifal.cx>
Tue, 26 Aug 2014 00:24:07 +0000 (20:24 -0400)
if there is already a waiter for a lock, spinning on the lock is
essentially an attempt to steal it from whichever waiter would obtain
it via any priority rules in place, and is therefore undesirable. in
the current implementation, there is always an inherent race window at
unlock during which a newly-arriving thread may steal the lock from
the existing waiters, but we should aim to keep this window minimal
rather than enlarging it.

src/thread/__wait.c
src/thread/pthread_mutex_timedlock.c
src/thread/pthread_rwlock_timedrdlock.c
src/thread/pthread_rwlock_timedwrlock.c
src/thread/sem_timedwait.c

index c1d6b61..01ee598 100644 (file)
@@ -4,7 +4,7 @@ void __wait(volatile int *addr, volatile int *waiters, int val, int priv)
 {
        int spins=100;
        if (priv) priv = 128;
-       while (spins--) {
+       while (spins-- && (!waiters || !*waiters)) {
                if (*addr==val) a_spin();
                else return;
        }
index 116a8b7..ae883f9 100644 (file)
@@ -12,7 +12,7 @@ int pthread_mutex_timedlock(pthread_mutex_t *restrict m, const struct timespec *
        if (r != EBUSY) return r;
        
        int spins = 100;
-       while (spins-- && m->_m_lock) a_spin();
+       while (spins-- && m->_m_lock && !m->_m_waiters) a_spin();
 
        while ((r=pthread_mutex_trylock(m)) == EBUSY) {
                if (!(r=m->_m_lock) || ((r&0x40000000) && (m->_m_type&4)))
index 884b7a1..ea50da4 100644 (file)
@@ -8,7 +8,7 @@ int pthread_rwlock_timedrdlock(pthread_rwlock_t *restrict rw, const struct times
        if (r != EBUSY) return r;
        
        int spins = 100;
-       while (spins-- && rw->_rw_lock) a_spin();
+       while (spins-- && rw->_rw_lock && !rw->_rw_waiters) a_spin();
 
        while ((r=pthread_rwlock_tryrdlock(rw))==EBUSY) {
                if (!(r=rw->_rw_lock) || (r&0x7fffffff)!=0x7fffffff) continue;
index f02b174..8d04f56 100644 (file)
@@ -8,7 +8,7 @@ int pthread_rwlock_timedwrlock(pthread_rwlock_t *restrict rw, const struct times
        if (r != EBUSY) return r;
        
        int spins = 100;
-       while (spins-- && rw->_rw_lock) a_spin();
+       while (spins-- && rw->_rw_lock && !rw->_rw_waiters) a_spin();
 
        while ((r=pthread_rwlock_trywrlock(rw))==EBUSY) {
                if (!(r=rw->_rw_lock)) continue;
index df5f3a6..b5a60ad 100644 (file)
@@ -11,7 +11,7 @@ int sem_timedwait(sem_t *restrict sem, const struct timespec *restrict at)
        if (!sem_trywait(sem)) return 0;
 
        int spins = 100;
-       while (spins-- && sem->__val[0] <= 0) a_spin();
+       while (spins-- && sem->__val[0] <= 0 && !sem->__val[1]) a_spin();
 
        while (sem_trywait(sem)) {
                int r;