2007-05-07 Ulrich Drepper <drepper@redhat.com> * sysdeps/unix/sysv/linux/lowlevelrobustlock.c (__lll_robust_lock_wait): Fix race caused by reloading of futex value. (__lll_robust_timedlock_wait): Likewise. Reported by Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>. --- libc/nptl/sysdeps/unix/sysv/linux/lowlevelrobustlock.c 2 Mar 2006 00:25:10 -0000 1.3 +++ libc/nptl/sysdeps/unix/sysv/linux/lowlevelrobustlock.c 7 May 2007 14:25:01 -0000 1.4 @@ -30,6 +30,10 @@ __lll_robust_lock_wait (int *futex) int oldval = *futex; int tid = THREAD_GETMEM (THREAD_SELF, tid); + /* If the futex changed meanwhile try locking again. */ + if (oldval == 0) + goto try; + do { if (__builtin_expect (oldval & FUTEX_OWNER_DIED, 0)) @@ -41,6 +45,9 @@ __lll_robust_lock_wait (int *futex) continue; lll_futex_wait (futex, newval); + + try: + ; } while ((oldval = atomic_compare_and_exchange_val_acq (futex, tid | FUTEX_WAITERS, @@ -57,6 +64,11 @@ __lll_robust_timedlock_wait (int *futex, return EINVAL; int tid = THREAD_GETMEM (THREAD_SELF, tid); + int oldval = *futex; + + /* If the futex changed meanwhile try locking again. */ + if (oldval == 0) + goto try; do { @@ -80,7 +92,6 @@ __lll_robust_timedlock_wait (int *futex, return ETIMEDOUT; /* Wait. */ - int oldval = *futex; if (__builtin_expect (oldval & FUTEX_OWNER_DIED, 0)) return oldval; @@ -90,8 +101,13 @@ __lll_robust_timedlock_wait (int *futex, continue; lll_futex_timed_wait (futex, newval, &rt); + + try: + ; } - while (atomic_compare_and_exchange_bool_acq (futex, tid | FUTEX_WAITERS, 0)); + while ((oldval = atomic_compare_and_exchange_val_acq (futex, + tid | FUTEX_WAITERS, + 0)) != 0); return 0; }