1*8feb0f0bSmrg /* Copyright (C) 2008-2020 Free Software Foundation, Inc.
236ac495dSmrg Contributed by Jakub Jelinek <jakub@redhat.com>.
336ac495dSmrg
436ac495dSmrg This file is part of the GNU Offloading and Multi Processing Library
536ac495dSmrg (libgomp).
636ac495dSmrg
736ac495dSmrg Libgomp is free software; you can redistribute it and/or modify it
836ac495dSmrg under the terms of the GNU General Public License as published by
936ac495dSmrg the Free Software Foundation; either version 3, or (at your option)
1036ac495dSmrg any later version.
1136ac495dSmrg
1236ac495dSmrg Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
1336ac495dSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1436ac495dSmrg FOR A PARTICULAR PURPOSE. See the GNU General Public License for
1536ac495dSmrg more details.
1636ac495dSmrg
1736ac495dSmrg Under Section 7 of GPL version 3, you are granted additional
1836ac495dSmrg permissions described in the GCC Runtime Library Exception, version
1936ac495dSmrg 3.1, as published by the Free Software Foundation.
2036ac495dSmrg
2136ac495dSmrg You should have received a copy of the GNU General Public License and
2236ac495dSmrg a copy of the GCC Runtime Library Exception along with this program;
2336ac495dSmrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
2436ac495dSmrg <http://www.gnu.org/licenses/>. */
2536ac495dSmrg
2636ac495dSmrg /* This is a Linux specific implementation of a mutex synchronization
2736ac495dSmrg mechanism for libgomp. This type is private to the library. This
2836ac495dSmrg implementation uses atomic instructions and the futex syscall. */
2936ac495dSmrg
3036ac495dSmrg #include <endian.h>
3136ac495dSmrg #include <limits.h>
3236ac495dSmrg #include "wait.h"
3336ac495dSmrg
3436ac495dSmrg void *
gomp_ptrlock_get_slow(gomp_ptrlock_t * ptrlock)3536ac495dSmrg gomp_ptrlock_get_slow (gomp_ptrlock_t *ptrlock)
3636ac495dSmrg {
3736ac495dSmrg int *intptr;
3836ac495dSmrg uintptr_t oldval = 1;
3936ac495dSmrg
4036ac495dSmrg __atomic_compare_exchange_n (ptrlock, &oldval, 2, false,
4136ac495dSmrg MEMMODEL_RELAXED, MEMMODEL_RELAXED);
4236ac495dSmrg
4336ac495dSmrg /* futex works on ints, not pointers.
4436ac495dSmrg But a valid work share pointer will be at least
4536ac495dSmrg 8 byte aligned, so it is safe to assume the low
4636ac495dSmrg 32-bits of the pointer won't contain values 1 or 2. */
4736ac495dSmrg __asm volatile ("" : "=r" (intptr) : "0" (ptrlock));
4836ac495dSmrg #if __BYTE_ORDER == __BIG_ENDIAN
4936ac495dSmrg if (sizeof (*ptrlock) > sizeof (int))
5036ac495dSmrg intptr += (sizeof (*ptrlock) / sizeof (int)) - 1;
5136ac495dSmrg #endif
5236ac495dSmrg do
5336ac495dSmrg do_wait (intptr, 2);
5436ac495dSmrg while (__atomic_load_n (intptr, MEMMODEL_RELAXED) == 2);
5536ac495dSmrg __asm volatile ("" : : : "memory");
5636ac495dSmrg return (void *) __atomic_load_n (ptrlock, MEMMODEL_ACQUIRE);
5736ac495dSmrg }
5836ac495dSmrg
5936ac495dSmrg void
gomp_ptrlock_set_slow(gomp_ptrlock_t * ptrlock)6036ac495dSmrg gomp_ptrlock_set_slow (gomp_ptrlock_t *ptrlock)
6136ac495dSmrg {
6236ac495dSmrg int *intptr;
6336ac495dSmrg
6436ac495dSmrg __asm volatile ("" : "=r" (intptr) : "0" (ptrlock));
6536ac495dSmrg #if __BYTE_ORDER == __BIG_ENDIAN
6636ac495dSmrg if (sizeof (*ptrlock) > sizeof (int))
6736ac495dSmrg intptr += (sizeof (*ptrlock) / sizeof (int)) - 1;
6836ac495dSmrg #endif
6936ac495dSmrg futex_wake (intptr, INT_MAX);
7036ac495dSmrg }
71