This patch modifies the fallback implementation of the POSIX spin-locks so that the unlock operation verifies that the lock is indeed locked.
2020-07-01 Bruno Haible <br...@clisp.org> pthread-spin: Add error checking. * lib/pthread-spin.c: Include <stdbool.h>. (pthread_spin_init, pthread_spin_lock, pthread_spin_trylock, pthread_spin_unlock) [GCC>=4.7]: Prefer an implementation that verifies the unlocks. * modules/pthread-spin (Depends-on): Add stdbool. diff --git a/lib/pthread-spin.c b/lib/pthread-spin.c index 93e8b37..73eb9f3 100644 --- a/lib/pthread-spin.c +++ b/lib/pthread-spin.c @@ -21,6 +21,8 @@ /* Specification. */ #include <pthread.h> +#include <stdbool.h> + #if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS # include "windows-spin.h" #endif @@ -72,6 +74,55 @@ pthread_spin_destroy (pthread_spinlock_t *lock) Documentation: <https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/_005f_005fatomic-Builtins.html> */ +# if 1 +/* An implementation that verifies the unlocks. */ + +int +pthread_spin_init (pthread_spinlock_t *lock, + int shared_across_processes _GL_UNUSED) +{ + __atomic_store_n ((char *) lock, 0, __ATOMIC_SEQ_CST); + return 0; +} + +int +pthread_spin_lock (pthread_spinlock_t *lock) +{ + /* Wait until *lock becomes 0, then replace it with 1. */ + asyncsafe_spinlock_t zero; + while (!(zero = 0, + __atomic_compare_exchange_n ((char *) lock, &zero, 1, false, + __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))) + ; + return 0; +} + +int +pthread_spin_trylock (pthread_spinlock_t *lock) +{ + asyncsafe_spinlock_t zero; + if (!(zero = 0, + __atomic_compare_exchange_n ((char *) lock, &zero, 1, false, + __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))) + return EBUSY; + return 0; +} + +int +pthread_spin_unlock (pthread_spinlock_t *lock) +{ + /* If *lock is 1, then replace it with 0. */ + asyncsafe_spinlock_t one = 1; + if (!__atomic_compare_exchange_n ((char *) lock, &one, 0, false, + __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) + abort (); + return 0; +} + +# else +/* An implementation that is a little bit more optimized, but does not verify + the unlocks. */ + int pthread_spin_init (pthread_spinlock_t *lock, int shared_across_processes _GL_UNUSED) @@ -103,6 +154,8 @@ pthread_spin_unlock (pthread_spinlock_t *lock) return 0; } +# endif + int pthread_spin_destroy (pthread_spinlock_t *lock) { diff --git a/modules/pthread-spin b/modules/pthread-spin index 53e0051..ce69944 100644 --- a/modules/pthread-spin +++ b/modules/pthread-spin @@ -7,6 +7,7 @@ m4/pthread-spin.m4 Depends-on: pthread-h +stdbool [test $HAVE_PTHREAD_SPIN_INIT = 0 || test $REPLACE_PTHREAD_SPIN_INIT = 1] windows-spin [test $gl_threads_api = windows] configure.ac: