1/* Copyright (C) 2005-2020 Free Software Foundation, Inc. 2 Contributed by Richard Henderson <rth@redhat.com>. 3 4 This file is part of the GNU Offloading and Multi Processing Library 5 (libgomp). 6 7 Libgomp is free software; you can redistribute it and/or modify it 8 under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3, or (at your option) 10 any later version. 11 12 Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY 13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14 FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 more details. 16 17 Under Section 7 of GPL version 3, you are granted additional 18 permissions described in the GCC Runtime Library Exception, version 19 3.1, as published by the Free Software Foundation. 20 21 You should have received a copy of the GNU General Public License and 22 a copy of the GCC Runtime Library Exception along with this program; 23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24 <http://www.gnu.org/licenses/>. */ 25 26/* This is a Linux specific implementation of the public OpenMP locking 27 primitives. This implementation uses atomic instructions and the futex 28 syscall. */ 29 30#include <string.h> 31#include <unistd.h> 32#include <sys/syscall.h> 33#include "wait.h" 34 35/* Reuse the generic implementation in terms of gomp_mutex_t. */ 36#include "../../lock.c" 37 38#ifdef LIBGOMP_GNU_SYMBOL_VERSIONING 39/* gomp_mutex_* can be safely locked in one thread and 40 unlocked in another thread, so the OpenMP 2.5 and OpenMP 3.0 41 non-nested locks can be the same. */ 42strong_alias (gomp_init_lock_30, gomp_init_lock_25) 43strong_alias (gomp_destroy_lock_30, gomp_destroy_lock_25) 44strong_alias (gomp_set_lock_30, gomp_set_lock_25) 45strong_alias (gomp_unset_lock_30, gomp_unset_lock_25) 46strong_alias (gomp_test_lock_30, gomp_test_lock_25) 47 48/* The external recursive omp_nest_lock_25_t form requires additional work. */ 49 50/* We need an integer to uniquely identify this thread. Most generally 51 this is the thread's TID, which ideally we'd get this straight from 52 the TLS block where glibc keeps it. Unfortunately, we can't get at 53 that directly. 54 55 If we don't support (or have disabled) TLS, one function call is as 56 good (or bad) as any other. Use the syscall all the time. 57 58 On an ILP32 system (defined here as not LP64), we can make do with 59 any thread-local pointer. Ideally we'd use the TLS base address, 60 since that requires the least amount of arithmetic, but that's not 61 always available directly. Make do with the gomp_thread pointer 62 since it's handy. */ 63 64# if !defined (HAVE_TLS) 65static inline int gomp_tid (void) 66{ 67 return syscall (SYS_gettid); 68} 69# elif !defined(__LP64__) 70static inline int gomp_tid (void) 71{ 72 return (int) gomp_thread (); 73} 74# else 75static __thread int tid_cache; 76static inline int gomp_tid (void) 77{ 78 int tid = tid_cache; 79 if (__builtin_expect (tid == 0, 0)) 80 tid_cache = tid = syscall (SYS_gettid); 81 return tid; 82} 83# endif 84 85 86void 87gomp_init_nest_lock_25 (omp_nest_lock_25_t *lock) 88{ 89 memset (lock, 0, sizeof (*lock)); 90} 91 92void 93gomp_destroy_nest_lock_25 (omp_nest_lock_25_t *lock) 94{ 95} 96 97void 98gomp_set_nest_lock_25 (omp_nest_lock_25_t *lock) 99{ 100 int otid, tid = gomp_tid (); 101 102 while (1) 103 { 104 otid = 0; 105 if (__atomic_compare_exchange_n (&lock->owner, &otid, tid, false, 106 MEMMODEL_ACQUIRE, MEMMODEL_RELAXED)) 107 { 108 lock->count = 1; 109 return; 110 } 111 if (otid == tid) 112 { 113 lock->count++; 114 return; 115 } 116 117 do_wait (&lock->owner, otid); 118 } 119} 120 121void 122gomp_unset_nest_lock_25 (omp_nest_lock_25_t *lock) 123{ 124 /* ??? Validate that we own the lock here. */ 125 126 if (--lock->count == 0) 127 { 128 __atomic_store_n (&lock->owner, 0, MEMMODEL_RELEASE); 129 futex_wake (&lock->owner, 1); 130 } 131} 132 133int 134gomp_test_nest_lock_25 (omp_nest_lock_25_t *lock) 135{ 136 int otid, tid = gomp_tid (); 137 138 otid = 0; 139 if (__atomic_compare_exchange_n (&lock->owner, &otid, tid, false, 140 MEMMODEL_ACQUIRE, MEMMODEL_RELAXED)) 141 { 142 lock->count = 1; 143 return 1; 144 } 145 if (otid == tid) 146 return ++lock->count; 147 148 return 0; 149} 150 151omp_lock_symver (omp_init_lock) 152omp_lock_symver (omp_destroy_lock) 153omp_lock_symver (omp_set_lock) 154omp_lock_symver (omp_unset_lock) 155omp_lock_symver (omp_test_lock) 156omp_lock_symver (omp_init_nest_lock) 157omp_lock_symver (omp_destroy_nest_lock) 158omp_lock_symver (omp_set_nest_lock) 159omp_lock_symver (omp_unset_nest_lock) 160omp_lock_symver (omp_test_nest_lock) 161 162#else 163 164ialias (omp_init_lock) 165ialias (omp_init_nest_lock) 166ialias (omp_destroy_lock) 167ialias (omp_destroy_nest_lock) 168ialias (omp_set_lock) 169ialias (omp_set_nest_lock) 170ialias (omp_unset_lock) 171ialias (omp_unset_nest_lock) 172ialias (omp_test_lock) 173ialias (omp_test_nest_lock) 174 175#endif 176