>From 5614c5c9b577cb4c631401cb80ddafaea44a769e Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Fri, 6 Jan 2017 18:30:40 +0100 Subject: [PATCH 1/3] lock: Fix data races. * m4/lock.m4 (gl_PREREQ_LOCK): Test for . * lib/glthread/lock.c (atomic_thread_fence): Define as a dummy if is not available. (glthread_rwlock_init_multithreaded, glthread_rwlock_rdlock_multithreaded, glthread_rwlock_wrlock_multithreaded, glthread_rwlock_wrlock_multithreaded, glthread_rwlock_destroy_multithreaded): Use atomic_thread_fence to guarantee memory reads actually see the effects of previous memory writes in multiprocessor systems. (glthread_recursive_lock_init_multithreaded, glthread_recursive_lock_lock_multithreaded, glthread_recursive_lock_unlock_multithreaded, glthread_recursive_lock_destroy_multithreaded): Likewise. (glthread_once_multithreaded): LIkewise. Reported by Torvald Riegel . --- ChangeLog | 20 ++++++++++++++ lib/glthread/lock.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++ m4/lock.m4 | 6 ++-- 3 files changed, 103 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index ebd491f..77f7c2f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2017-01-06 Bruno Haible + + lock: Fix data races. + * m4/lock.m4 (gl_PREREQ_LOCK): Test for . + * lib/glthread/lock.c (atomic_thread_fence): Define as a dummy if + is not available. + (glthread_rwlock_init_multithreaded, + glthread_rwlock_rdlock_multithreaded, + glthread_rwlock_wrlock_multithreaded, + glthread_rwlock_wrlock_multithreaded, + glthread_rwlock_destroy_multithreaded): Use atomic_thread_fence to + guarantee memory reads actually see the effects of previous memory + writes in multiprocessor systems. + (glthread_recursive_lock_init_multithreaded, + glthread_recursive_lock_lock_multithreaded, + glthread_recursive_lock_unlock_multithreaded, + glthread_recursive_lock_destroy_multithreaded): Likewise. + (glthread_once_multithreaded): LIkewise. + Reported by Torvald Riegel . + 2017-01-05 Pádraig Brady parse-datetime: fix generated paths for coverage files diff --git a/lib/glthread/lock.c b/lib/glthread/lock.c index 061562b..eceb2c3 100644 --- a/lib/glthread/lock.c +++ b/lib/glthread/lock.c @@ -22,6 +22,16 @@ #include "glthread/lock.h" +/* Use to avoid data races in multiprocessor systems. + Does not affect x86 and x86_64 systems. */ +#if HAVE_STDATOMIC_H +# include +#else +/* On multiprocessor systems which don't have and which are + not x86 or x86_64, you have to cross your fingers. */ +# define atomic_thread_fence(mo) /* nothing! */ +#endif + /* ========================================================================= */ #if USE_POSIX_THREADS @@ -68,16 +78,26 @@ glthread_rwlock_init_multithreaded (gl_rwlock_t *lock) { int err; + /* Ensure changes to *lock by a previous glthread_rwlock_destroy_multithreaded + invocation on another processor have been received by this processor in a + multiprocessor system. */ + atomic_thread_fence (memory_order_acquire); err = pthread_rwlock_init (&lock->rwlock, NULL); if (err != 0) return err; lock->initialized = 1; + /* Ensure the changes to *lock are pushed to other processors in a + multiprocessor system. */ + atomic_thread_fence (memory_order_release); return 0; } int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock) { + /* Ensure other changes to *lock have been received by this processor in a + multiprocessor system. */ + atomic_thread_fence (memory_order_acquire); if (!lock->initialized) { int err; @@ -104,6 +124,9 @@ glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock) int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock) { + /* Ensure other changes to *lock have been received by this processor in a + multiprocessor system. */ + atomic_thread_fence (memory_order_acquire); if (!lock->initialized) { int err; @@ -130,6 +153,9 @@ glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock) int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock) { + /* Ensure other changes to *lock have been received by this processor in a + multiprocessor system. */ + atomic_thread_fence (memory_order_acquire); if (!lock->initialized) return EINVAL; return pthread_rwlock_unlock (&lock->rwlock); @@ -140,12 +166,18 @@ glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock) { int err; + /* Ensure other changes to *lock have been received by this processor in a + multiprocessor system. */ + atomic_thread_fence (memory_order_acquire); if (!lock->initialized) return EINVAL; err = pthread_rwlock_destroy (&lock->rwlock); if (err != 0) return err; lock->initialized = 0; + /* Ensure to not disturb future calls to glthread_rwlock_init_multithreaded + on other processors in a multiprocessor system. */ + atomic_thread_fence (memory_order_release); return 0; } @@ -342,6 +374,11 @@ glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock) pthread_mutexattr_t attributes; int err; + /* Ensure changes to *lock by a previous + glthread_recursive_lock_destroy_multithreaded invocation on another + processor have been received by this processor in a multiprocessor + system. */ + atomic_thread_fence (memory_order_acquire); err = pthread_mutexattr_init (&attributes); if (err != 0) return err; @@ -361,12 +398,18 @@ glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock) if (err != 0) return err; lock->initialized = 1; + /* Ensure the changes to *lock are pushed to other processors in a + multiprocessor system. */ + atomic_thread_fence (memory_order_release); return 0; } int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock) { + /* Ensure other changes to *lock have been received by this processor in a + multiprocessor system. */ + atomic_thread_fence (memory_order_acquire); if (!lock->initialized) { int err; @@ -393,6 +436,9 @@ glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock) int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock) { + /* Ensure other changes to *lock have been received by this processor in a + multiprocessor system. */ + atomic_thread_fence (memory_order_acquire); if (!lock->initialized) return EINVAL; return pthread_mutex_unlock (&lock->recmutex); @@ -403,12 +449,19 @@ glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock) { int err; + /* Ensure other changes to *lock have been received by this processor in a + multiprocessor system. */ + atomic_thread_fence (memory_order_acquire); if (!lock->initialized) return EINVAL; err = pthread_mutex_destroy (&lock->recmutex); if (err != 0) return err; lock->initialized = 0; + /* Ensure to not disturb future calls to + glthread_recursive_lock_init_multithreaded on other processors in a + multiprocessor system. */ + atomic_thread_fence (memory_order_release); return 0; } @@ -513,6 +566,10 @@ glthread_once_singlethreaded (pthread_once_t *once_control) int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock) { + /* Ensure changes to *lock by a previous glthread_rwlock_destroy_multithreaded + invocation on another processor have been received by this processor in a + multiprocessor system. */ + atomic_thread_fence (memory_order_acquire); if (!pth_mutex_init (&lock->lock)) return errno; if (!pth_cond_init (&lock->waiting_readers)) @@ -522,12 +579,18 @@ glthread_rwlock_init_multithreaded (gl_rwlock_t *lock) lock->waiting_writers_count = 0; lock->runcount = 0; lock->initialized = 1; + /* Ensure the changes to *lock are pushed to other processors in a + multiprocessor system. */ + atomic_thread_fence (memory_order_release); return 0; } int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock) { + /* Ensure other changes to *lock have been received by this processor in a + multiprocessor system. */ + atomic_thread_fence (memory_order_acquire); if (!lock->initialized) glthread_rwlock_init_multithreaded (lock); if (!pth_mutex_acquire (&lock->lock, 0, NULL)) @@ -554,6 +617,9 @@ glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock) int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock) { + /* Ensure other changes to *lock have been received by this processor in a + multiprocessor system. */ + atomic_thread_fence (memory_order_acquire); if (!lock->initialized) glthread_rwlock_init_multithreaded (lock); if (!pth_mutex_acquire (&lock->lock, 0, NULL)) @@ -582,6 +648,9 @@ glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock) { int err; + /* Ensure other changes to *lock have been received by this processor in a + multiprocessor system. */ + atomic_thread_fence (memory_order_acquire); if (!lock->initialized) return EINVAL; if (!pth_mutex_acquire (&lock->lock, 0, NULL)) @@ -638,6 +707,9 @@ int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock) { lock->initialized = 0; + /* Ensure to not disturb future calls to glthread_rwlock_init_multithreaded + on other processors in a multiprocessor system. */ + atomic_thread_fence (memory_order_release); return 0; } @@ -753,6 +825,9 @@ glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock) int glthread_once_multithreaded (gl_once_t *once_control, void (*initfunction) (void)) { + /* Ensure other changes to *once_control have been received by this processor + in a multiprocessor system. */ + atomic_thread_fence (memory_order_acquire); if (!once_control->inited) { int err; @@ -762,10 +837,14 @@ glthread_once_multithreaded (gl_once_t *once_control, void (*initfunction) (void err = mutex_lock (&once_control->mutex); if (err != 0) return err; + atomic_thread_fence (memory_order_acquire); if (!once_control->inited) { once_control->inited = 1; initfunction (); + /* Ensure the changes to *once_control are pushed to other processors + in a multiprocessor system. */ + atomic_thread_fence (memory_order_release); } return mutex_unlock (&once_control->mutex); } diff --git a/m4/lock.m4 b/m4/lock.m4 index cb04a67..720f9b2 100644 --- a/m4/lock.m4 +++ b/m4/lock.m4 @@ -1,4 +1,4 @@ -# lock.m4 serial 14 +# lock.m4 serial 15 dnl Copyright (C) 2005-2017 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -44,4 +44,6 @@ return !x; ]) # Prerequisites of lib/glthread/lock.c. -AC_DEFUN([gl_PREREQ_LOCK], [:]) +AC_DEFUN([gl_PREREQ_LOCK], [ + AC_CHECK_HEADERS_ONCE([stdatomic.h]) +]) -- 2.6.4