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 c1d6b61c239eaaeb3970af1614d27e7d41c631d9..01ee598287720773b220acef49cacc9892e01106 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 116a8b7b3cd4112fc6e34f88f75537f05291307e..ae883f90723793ad09ce16ecd2cd3ad328bfe017 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 884b7a1e52f3ad38cdba7da35f93ff973229d072..ea50da4a9e026d88780b9ecc72c880cb80fc4267 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 f02b174b08aafc0e807c24df1893fd2a7551f538..8d04f561e6e7744305e87306db46ee968becdb8a 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 df5f3a6ccb832abee3db21aa759547ac8224c9de..b5a60addb0aa7fc398f7a9d7ea93f504d4da16ee 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;