X-Git-Url: https://git.liburcu.org/?p=urcu.git;a=blobdiff_plain;f=compat_futex.c;h=9a08624bbab59be80c9472331f7b8e4ef0f5d54c;hp=3f1d1ef3410a91d4ae432080debcba4c6a17e387;hb=8999a9ee7abe868caf8f5327d8b2e8b8b44ee87d;hpb=6d841bc23fc94345fe76651d73c1a3f821a85aa7 diff --git a/compat_futex.c b/compat_futex.c index 3f1d1ef..9a08624 100644 --- a/compat_futex.c +++ b/compat_futex.c @@ -31,8 +31,18 @@ #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. @@ -43,7 +53,7 @@ static pthread_cond_t compat_futex_cond = PTHREAD_COND_INITIALIZER; 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, gret = 0; /* * Check if NULL. Don't let users expect that they are taken into @@ -58,23 +68,31 @@ int compat_futex_noasync(int32_t *uaddr, int op, int32_t val, */ cmm_smp_mb(); - ret = pthread_mutex_lock(&compat_futex_lock); + ret = pthread_mutex_lock(&__urcu_compat_futex_lock); assert(!ret); 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 (*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; } -end: - ret = pthread_mutex_unlock(&compat_futex_lock); + ret = pthread_mutex_unlock(&__urcu_compat_futex_lock); assert(!ret); return gret; } @@ -88,8 +106,6 @@ end: 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; - /* * Check if NULL. Don't let users expect that they are taken into * account. @@ -113,4 +129,5 @@ int compat_futex_async(int32_t *uaddr, int op, int32_t val, default: return -EINVAL; } + return 0; }