diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog index e9148f6375f6e7058d6931bfb1d76f1a3be901cf..faa6749d8248d3306fd8551a110a322d3c0fe90b 100644 --- a/libgomp/ChangeLog +++ b/libgomp/ChangeLog @@ -1,3 +1,15 @@ +2011-11-30 Alan Modra <amodra@gmail.com> + + * ordered.c (gomp_ordered_sync): Add MEMMODEL_ACQ_REL fence. + * critical.c (GOMP_critical_start): Add MEMMODEL_RELEASE fence. + * config/linux/mutex.h: Use atomic rather than sync builtins. + * config/linux/mutex.c: Likewise. Comment. Use -1 for waiting state. + * config/linux/omp-lock.h: Comment fix. + * config/linux/arm/mutex.h: Delete. + * config/linux/powerpc/mutex.h: Delete. + * config/linux/ia64/mutex.h: Delete. + * config/linux/mips/mutex.h: Delete. + 2011-11-30 Alan Modra <amodra@gmail.com> PR libgomp/51249 diff --git a/libgomp/config/linux/arm/mutex.h b/libgomp/config/linux/arm/mutex.h deleted file mode 100644 index 30021d54746d12d71f3875e7e7b215d54a31ba0a..0000000000000000000000000000000000000000 --- a/libgomp/config/linux/arm/mutex.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright (C) 2010 Free Software Foundation, Inc. - Contributed by ARM Ltd. - - This file is part of the GNU OpenMP Library (libgomp). - - Libgomp is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, or (at your option) - any later version. - - Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - <http://www.gnu.org/licenses/>. */ - -/* ARM needs the same correct usage of __sync_synchronize and - __sync_lock_test_and_set as ia64. So we just use its mutex.h. */ - -#include "config/linux/ia64/mutex.h" diff --git a/libgomp/config/linux/ia64/mutex.h b/libgomp/config/linux/ia64/mutex.h deleted file mode 100644 index 8a67673df40238dac0df8b13caa8d29a1845238b..0000000000000000000000000000000000000000 --- a/libgomp/config/linux/ia64/mutex.h +++ /dev/null @@ -1,66 +0,0 @@ -/* Copyright (C) 2005, 2008, 2009, 2011 Free Software Foundation, Inc. - Contributed by Richard Henderson <rth@redhat.com>. - - This file is part of the GNU OpenMP Library (libgomp). - - Libgomp is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, or (at your option) - any later version. - - Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - <http://www.gnu.org/licenses/>. */ - -/* This is a Linux specific implementation of a mutex synchronization - mechanism for libgomp. This type is private to the library. This - implementation uses atomic instructions and the futex syscall. */ - -#ifndef GOMP_MUTEX_H -#define GOMP_MUTEX_H 1 - -typedef int gomp_mutex_t; - -#define GOMP_MUTEX_INIT_0 1 - -static inline void gomp_mutex_init (gomp_mutex_t *mutex) -{ - *mutex = 0; -} - -extern void gomp_mutex_lock_slow (gomp_mutex_t *mutex, int); -static inline void gomp_mutex_lock (gomp_mutex_t *mutex) -{ - int oldval = __sync_val_compare_and_swap (mutex, 0, 1); - if (__builtin_expect (oldval, 0)) - gomp_mutex_lock_slow (mutex, oldval); -} - -extern void gomp_mutex_unlock_slow (gomp_mutex_t *mutex); - -/* IA64 needs a __sync_synchronize call before __sync_lock_test_and_set - because __sync_lock_test_and_set is not a full memory fence. */ -static inline void gomp_mutex_unlock (gomp_mutex_t *mutex) -{ - int val; - __sync_synchronize (); - val = __sync_lock_test_and_set (mutex, 0); - if (__builtin_expect (val > 1, 0)) - gomp_mutex_unlock_slow (mutex); -} - -static inline void gomp_mutex_destroy (gomp_mutex_t *mutex) -{ -} - -#endif /* GOMP_MUTEX_H */ diff --git a/libgomp/config/linux/mips/mutex.h b/libgomp/config/linux/mips/mutex.h deleted file mode 100644 index 668cc11b29a95a876e0220ac251193120e4b30c4..0000000000000000000000000000000000000000 --- a/libgomp/config/linux/mips/mutex.h +++ /dev/null @@ -1,27 +0,0 @@ -/* Copyright (C) 2009 Free Software Foundation, Inc. - - This file is part of the GNU OpenMP Library (libgomp). - - Libgomp is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, or (at your option) - any later version. - - Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - <http://www.gnu.org/licenses/>. */ - -/* MIPS needs the same correct usage of __sync_synchronize and - __sync_lock_test_and_set as ia64. So we just use its mutex.h. */ - -#include "config/linux/ia64/mutex.h" diff --git a/libgomp/config/linux/mutex.c b/libgomp/config/linux/mutex.c index 2574f7be42a0d35aa81f03a30b2be014e2a1326b..1b84ffb0990fdc149c79d185d78052977ff4f105 100644 --- a/libgomp/config/linux/mutex.c +++ b/libgomp/config/linux/mutex.c @@ -34,25 +34,32 @@ long int gomp_futex_wait = FUTEX_WAIT | FUTEX_PRIVATE_FLAG; void gomp_mutex_lock_slow (gomp_mutex_t *mutex, int oldval) { + /* First loop spins a while. */ while (oldval == 1) { if (do_spin (mutex, 1)) { - oldval = __sync_lock_test_and_set (mutex, 2); + /* Spin timeout, nothing changed. Set waiting flag. */ + oldval = __atomic_exchange_n (mutex, -1, MEMMODEL_ACQUIRE); if (oldval == 0) return; - futex_wait (mutex, 2); + futex_wait (mutex, -1); break; } else { - oldval = __sync_val_compare_and_swap (mutex, 0, 1); - if (oldval == 0) + /* Something changed. If now unlocked, we're good to go. */ + oldval = 0; + if (__atomic_compare_exchange_n (mutex, &oldval, 1, false, + MEMMODEL_ACQUIRE, MEMMODEL_RELAXED)) return; } } - while ((oldval = __sync_lock_test_and_set (mutex, 2))) - do_wait (mutex, 2); + + /* Second loop waits until mutex is unlocked. We always exit this + loop with wait flag set, so next unlock will awaken a thread. */ + while ((oldval = __atomic_exchange_n (mutex, -1, MEMMODEL_ACQUIRE))) + do_wait (mutex, -1); } void diff --git a/libgomp/config/linux/mutex.h b/libgomp/config/linux/mutex.h index eafb0e7673401332329b7d5eaedd59eac9232228..912152ec3a1a75d25f6302c905acda61db651fac 100644 --- a/libgomp/config/linux/mutex.h +++ b/libgomp/config/linux/mutex.h @@ -33,39 +33,34 @@ typedef int gomp_mutex_t; #define GOMP_MUTEX_INIT_0 1 -static inline void gomp_mutex_init (gomp_mutex_t *mutex) +extern void gomp_mutex_lock_slow (gomp_mutex_t *mutex, int); +extern void gomp_mutex_unlock_slow (gomp_mutex_t *mutex); + +static inline void +gomp_mutex_init (gomp_mutex_t *mutex) { *mutex = 0; } -extern void gomp_mutex_lock_slow (gomp_mutex_t *mutex, int); -static inline void gomp_mutex_lock (gomp_mutex_t *mutex) +static inline void +gomp_mutex_destroy (gomp_mutex_t *mutex) { - int oldval = __sync_val_compare_and_swap (mutex, 0, 1); - if (__builtin_expect (oldval, 0)) - gomp_mutex_lock_slow (mutex, oldval); } -extern void gomp_mutex_unlock_slow (gomp_mutex_t *mutex); -static inline void gomp_mutex_unlock (gomp_mutex_t *mutex) +static inline void +gomp_mutex_lock (gomp_mutex_t *mutex) { - /* Warning: By definition __sync_lock_test_and_set() does not have - proper memory barrier semantics for a mutex unlock operation. - However, this default implementation is written assuming that it - does, which is true for some targets. - - Targets that require additional memory barriers before - __sync_lock_test_and_set to achieve the release semantics of - mutex unlock, are encouraged to include - "config/linux/ia64/mutex.h" in a target specific mutex.h instead - of using this file. */ - int val = __sync_lock_test_and_set (mutex, 0); - if (__builtin_expect (val > 1, 0)) - gomp_mutex_unlock_slow (mutex); + int oldval = 0; + if (!__atomic_compare_exchange_n (mutex, &oldval, 1, false, + MEMMODEL_ACQUIRE, MEMMODEL_RELAXED)) + gomp_mutex_lock_slow (mutex, oldval); } -static inline void gomp_mutex_destroy (gomp_mutex_t *mutex) +static inline void +gomp_mutex_unlock (gomp_mutex_t *mutex) { + int wait = __atomic_exchange_n (mutex, 0, MEMMODEL_RELEASE); + if (__builtin_expect (wait < 0, 0)) + gomp_mutex_unlock_slow (mutex); } - #endif /* GOMP_MUTEX_H */ diff --git a/libgomp/config/linux/omp-lock.h b/libgomp/config/linux/omp-lock.h index e65aff7fce74145647e575a3deb1a7d86784416a..2ca7c5e1d60fe13875ce767fd03f85cb3bf9a128 100644 --- a/libgomp/config/linux/omp-lock.h +++ b/libgomp/config/linux/omp-lock.h @@ -3,8 +3,8 @@ structures without polluting the namespace. When using the Linux futex primitive, non-recursive locks require - only one int. Recursive locks require we identify the owning task - and so require one int and a pointer. */ + one int. Recursive locks require we identify the owning task + and so require in addition one int and a pointer. */ typedef int omp_lock_t; typedef struct { int lock, count; void *owner; } omp_nest_lock_t; diff --git a/libgomp/config/linux/powerpc/mutex.h b/libgomp/config/linux/powerpc/mutex.h deleted file mode 100644 index e64ff077c836bbe83295ffb08f90c530ddcb8791..0000000000000000000000000000000000000000 --- a/libgomp/config/linux/powerpc/mutex.h +++ /dev/null @@ -1,2 +0,0 @@ -/* On PowerPC __sync_lock_test_and_set isn't a full barrier. */ -#include "config/linux/ia64/mutex.h" diff --git a/libgomp/critical.c b/libgomp/critical.c index daf1ffc213772ee0c3e27a83e9921a40f69e7a8d..414c42216265c43553b8ca63ef0efe16625dc94b 100644 --- a/libgomp/critical.c +++ b/libgomp/critical.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2005, 2009 Free Software Foundation, Inc. +/* Copyright (C) 2005, 2009, 2011 Free Software Foundation, Inc. Contributed by Richard Henderson <rth@redhat.com>. This file is part of the GNU OpenMP Library (libgomp). @@ -33,6 +33,8 @@ static gomp_mutex_t default_lock; void GOMP_critical_start (void) { + /* There is an implicit flush on entry to a critical region. */ + __atomic_thread_fence (MEMMODEL_RELEASE); gomp_mutex_lock (&default_lock); } diff --git a/libgomp/ordered.c b/libgomp/ordered.c index e5673fe1c08e41afbc67a7a13cb76b1d23b77e77..f84d52eb9ff10bc034676452fbeef5af9caf4ccc 100644 --- a/libgomp/ordered.c +++ b/libgomp/ordered.c @@ -207,8 +207,13 @@ gomp_ordered_sync (void) post to our release semaphore. So the two cases are that we will either win the race an momentarily block on the semaphore, or lose the race and find the semaphore already unlocked and so not block. - Either way we get correct results. */ + Either way we get correct results. + However, there is an implicit flush on entry to an ordered region, + so we do need to have a barrier here. If we were taking a lock + this could be MEMMODEL_RELEASE since the acquire would be coverd + by the lock. */ + __atomic_thread_fence (MEMMODEL_ACQ_REL); if (ws->ordered_owner != thr->ts.team_id) { gomp_sem_wait (team->ordered_release[thr->ts.team_id]);