X-Git-Url: https://git.liburcu.org/?p=urcu.git;a=blobdiff_plain;f=compat_futex.c;h=b7f78f0b1c87a832cfb33c22e3a93845bbe7d3bb;hp=61bc6c36bae265d8a0a58ec5e8f7b74d43781f26;hb=84f4ccb4bcf32c0336a0c7a3a4ba76d90d6dea1b;hpb=6982d6d71aeed16d2d929bd0ed221e8f444b706e diff --git a/compat_futex.c b/compat_futex.c index 61bc6c3..b7f78f0 100644 --- a/compat_futex.c +++ b/compat_futex.c @@ -26,12 +26,24 @@ #include #include #include +#include #include -#include +#include +#include -static pthread_mutex_t compat_futex_lock = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t compat_futex_cond = PTHREAD_COND_INITIALIZER; +/* + * Using attribute "weak" for __urcu_compat_futex_lock and + * __urcu_compat_futex_cond. Those are globally visible by the entire + * program, even though many shared objects may have their own version. + * The first version that gets loaded will be used by the entire program + * (executable and all shared objects). + */ + +__attribute__((weak)) +pthread_mutex_t __urcu_compat_futex_lock = PTHREAD_MUTEX_INITIALIZER; +__attribute__((weak)) +pthread_cond_t __urcu_compat_futex_cond = PTHREAD_COND_INITIALIZER; /* * _NOT SIGNAL-SAFE_. pthread_cond is not signal-safe anyway. Though. @@ -39,14 +51,14 @@ static pthread_cond_t compat_futex_cond = PTHREAD_COND_INITIALIZER; * Waiter will relinquish the CPU until woken up. */ -int compat_futex_noasync(int *uaddr, int op, int val, - const struct timespec *timeout, int *uaddr2, int val3) +int compat_futex_noasync(int32_t *uaddr, int op, int32_t val, + const struct timespec *timeout, int32_t *uaddr2, int32_t val3) { - int ret, i, gret = 0; + int ret = 0, lockret; /* * Check if NULL. Don't let users expect that they are taken into - * account. + * account. */ assert(!timeout); assert(!uaddr2); @@ -55,27 +67,44 @@ int compat_futex_noasync(int *uaddr, int op, int val, /* * memory barriers to serialize with the previous uaddr modification. */ - smp_mb(); + cmm_smp_mb(); - ret = pthread_mutex_lock(&compat_futex_lock); - assert(!ret); + lockret = pthread_mutex_lock(&__urcu_compat_futex_lock); + if (lockret) { + errno = lockret; + ret = -1; + goto end; + } switch (op) { case FUTEX_WAIT: - if (*uaddr != val) - goto end; - pthread_cond_wait(&compat_futex_cond, &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: - for (i = 0; i < val; i++) - pthread_cond_signal(&compat_futex_cond); + /* + * 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; + errno = EINVAL; + ret = -1; + } + lockret = pthread_mutex_unlock(&__urcu_compat_futex_lock); + if (lockret) { + errno = lockret; + ret = -1; } end: - ret = pthread_mutex_unlock(&compat_futex_lock); - assert(!ret); - return gret; + return ret; } /* @@ -84,14 +113,14 @@ end: * Waiter will busy-loop trying to read the condition. */ -int compat_futex_async(int *uaddr, int op, int val, - const struct timespec *timeout, int *uaddr2, int val3) +int compat_futex_async(int32_t *uaddr, int op, int32_t val, + const struct timespec *timeout, int32_t *uaddr2, int32_t val3) { - int ret, i; + int ret = 0; /* * Check if NULL. Don't let users expect that they are taken into - * account. + * account. */ assert(!timeout); assert(!uaddr2); @@ -100,16 +129,24 @@ int compat_futex_async(int *uaddr, int op, int val, /* * Ensure previous memory operations on uaddr have completed. */ - smp_mb(); + cmm_smp_mb(); switch (op) { case FUTEX_WAIT: - while (*uaddr == val) - poll(NULL, 0, 10); + while (CMM_LOAD_SHARED(*uaddr) == val) { + if (poll(NULL, 0, 10) < 0) { + ret = -1; + /* Keep poll errno. Caller handles EINTR. */ + goto end; + } + } break; case FUTEX_WAKE: break; default: - return -EINVAL; + errno = EINVAL; + ret = -1; } +end: + return ret; }