>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