Fix: compat_futex.c: *uaddr should be read as volatile
[urcu.git] / compat_futex.c
index e7342fe38ccda2330b45e157cd0c1d7cb02cd3ef..6ec0b3912b34afbda58c873371f83aec55d35f68 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <urcu/arch.h>
 #include <urcu/futex.h>
+#include <urcu/system.h>
 
 /*
  * Using attribute "weak" for __urcu_compat_futex_lock and
@@ -72,17 +73,26 @@ int compat_futex_noasync(int32_t *uaddr, int op, int32_t val,
        assert(!ret);
        switch (op) {
        case FUTEX_WAIT:
-               if (*uaddr != val)
-                       goto end;
-               pthread_cond_wait(&__urcu_compat_futex_cond, &__urcu_compat_futex_lock);
+               /*
+                * Wait until *uaddr is changed to something else than "val".
+                * Comparing *uaddr content against val figures out which
+                * thread has been awakened.
+                */
+               while (CMM_LOAD_SHARED(*uaddr) == val)
+                       pthread_cond_wait(&__urcu_compat_futex_cond,
+                               &__urcu_compat_futex_lock);
                break;
        case FUTEX_WAKE:
+               /*
+                * Each wake is sending a broadcast, thus attempting wakeup of
+                * all awaiting threads, independently of their respective
+                * uaddr.
+                */
                pthread_cond_broadcast(&__urcu_compat_futex_cond);
                break;
        default:
                gret = -EINVAL;
        }
-end:
        ret = pthread_mutex_unlock(&__urcu_compat_futex_lock);
        assert(!ret);
        return gret;
@@ -112,7 +122,7 @@ int compat_futex_async(int32_t *uaddr, int op, int32_t val,
 
        switch (op) {
        case FUTEX_WAIT:
-               while (*uaddr == val)
+               while (CMM_LOAD_SHARED(*uaddr) == val)
                        poll(NULL, 0, 10);
                break;
        case FUTEX_WAKE:
This page took 0.022796 seconds and 4 git commands to generate.