1/* Copyright (C) 2005-2015 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 36/* The internal gomp_mutex_t and the external non-recursive omp_lock_t 37 have the same form. Re-use it. */ 38 39void 40gomp_init_lock_30 (omp_lock_t *lock) 41{ 42 gomp_mutex_init (lock); 43} 44 45void 46gomp_destroy_lock_30 (omp_lock_t *lock) 47{ 48 gomp_mutex_destroy (lock); 49} 50 51void 52gomp_set_lock_30 (omp_lock_t *lock) 53{ 54 gomp_mutex_lock (lock); 55} 56 57void 58gomp_unset_lock_30 (omp_lock_t *lock) 59{ 60 gomp_mutex_unlock (lock); 61} 62 63int 64gomp_test_lock_30 (omp_lock_t *lock) 65{ 66 int oldval = 0; 67 68 return __atomic_compare_exchange_n (lock, &oldval, 1, false, 69 MEMMODEL_ACQUIRE, MEMMODEL_RELAXED); 70} 71 72void 73gomp_init_nest_lock_30 (omp_nest_lock_t *lock) 74{ 75 memset (lock, '\0', sizeof (*lock)); 76} 77 78void 79gomp_destroy_nest_lock_30 (omp_nest_lock_t *lock) 80{ 81} 82 83void 84gomp_set_nest_lock_30 (omp_nest_lock_t *lock) 85{ 86 void *me = gomp_icv (true); 87 88 if (lock->owner != me) 89 { 90 gomp_mutex_lock (&lock->lock); 91 lock->owner = me; 92 } 93 94 lock->count++; 95} 96 97void 98gomp_unset_nest_lock_30 (omp_nest_lock_t *lock) 99{ 100 if (--lock->count == 0) 101 { 102 lock->owner = NULL; 103 gomp_mutex_unlock (&lock->lock); 104 } 105} 106 107int 108gomp_test_nest_lock_30 (omp_nest_lock_t *lock) 109{ 110 void *me = gomp_icv (true); 111 int oldval; 112 113 if (lock->owner == me) 114 return ++lock->count; 115 116 oldval = 0; 117 if (__atomic_compare_exchange_n (&lock->lock, &oldval, 1, false, 118 MEMMODEL_ACQUIRE, MEMMODEL_RELAXED)) 119 { 120 lock->owner = me; 121 lock->count = 1; 122 return 1; 123 } 124 125 return 0; 126} 127 128#ifdef LIBGOMP_GNU_SYMBOL_VERSIONING 129/* gomp_mutex_* can be safely locked in one thread and 130 unlocked in another thread, so the OpenMP 2.5 and OpenMP 3.0 131 non-nested locks can be the same. */ 132strong_alias (gomp_init_lock_30, gomp_init_lock_25) 133strong_alias (gomp_destroy_lock_30, gomp_destroy_lock_25) 134strong_alias (gomp_set_lock_30, gomp_set_lock_25) 135strong_alias (gomp_unset_lock_30, gomp_unset_lock_25) 136strong_alias (gomp_test_lock_30, gomp_test_lock_25) 137 138/* The external recursive omp_nest_lock_25_t form requires additional work. */ 139 140/* We need an integer to uniquely identify this thread. Most generally 141 this is the thread's TID, which ideally we'd get this straight from 142 the TLS block where glibc keeps it. Unfortunately, we can't get at 143 that directly. 144 145 If we don't support (or have disabled) TLS, one function call is as 146 good (or bad) as any other. Use the syscall all the time. 147 148 On an ILP32 system (defined here as not LP64), we can make do with 149 any thread-local pointer. Ideally we'd use the TLS base address, 150 since that requires the least amount of arithmetic, but that's not 151 always available directly. Make do with the gomp_thread pointer 152 since it's handy. */ 153 154# if !defined (HAVE_TLS) 155static inline int gomp_tid (void) 156{ 157 return syscall (SYS_gettid); 158} 159# elif !defined(__LP64__) 160static inline int gomp_tid (void) 161{ 162 return (int) gomp_thread (); 163} 164# else 165static __thread int tid_cache; 166static inline int gomp_tid (void) 167{ 168 int tid = tid_cache; 169 if (__builtin_expect (tid == 0, 0)) 170 tid_cache = tid = syscall (SYS_gettid); 171 return tid; 172} 173# endif 174 175 176void 177gomp_init_nest_lock_25 (omp_nest_lock_25_t *lock) 178{ 179 memset (lock, 0, sizeof (*lock)); 180} 181 182void 183gomp_destroy_nest_lock_25 (omp_nest_lock_25_t *lock) 184{ 185} 186 187void 188gomp_set_nest_lock_25 (omp_nest_lock_25_t *lock) 189{ 190 int otid, tid = gomp_tid (); 191 192 while (1) 193 { 194 otid = 0; 195 if (__atomic_compare_exchange_n (&lock->owner, &otid, tid, false, 196 MEMMODEL_ACQUIRE, MEMMODEL_RELAXED)) 197 { 198 lock->count = 1; 199 return; 200 } 201 if (otid == tid) 202 { 203 lock->count++; 204 return; 205 } 206 207 do_wait (&lock->owner, otid); 208 } 209} 210 211void 212gomp_unset_nest_lock_25 (omp_nest_lock_25_t *lock) 213{ 214 /* ??? Validate that we own the lock here. */ 215 216 if (--lock->count == 0) 217 { 218 __atomic_store_n (&lock->owner, 0, MEMMODEL_RELEASE); 219 futex_wake (&lock->owner, 1); 220 } 221} 222 223int 224gomp_test_nest_lock_25 (omp_nest_lock_25_t *lock) 225{ 226 int otid, tid = gomp_tid (); 227 228 otid = 0; 229 if (__atomic_compare_exchange_n (&lock->owner, &otid, tid, false, 230 MEMMODEL_ACQUIRE, MEMMODEL_RELAXED)) 231 { 232 lock->count = 1; 233 return 1; 234 } 235 if (otid == tid) 236 return ++lock->count; 237 238 return 0; 239} 240 241omp_lock_symver (omp_init_lock) 242omp_lock_symver (omp_destroy_lock) 243omp_lock_symver (omp_set_lock) 244omp_lock_symver (omp_unset_lock) 245omp_lock_symver (omp_test_lock) 246omp_lock_symver (omp_init_nest_lock) 247omp_lock_symver (omp_destroy_nest_lock) 248omp_lock_symver (omp_set_nest_lock) 249omp_lock_symver (omp_unset_nest_lock) 250omp_lock_symver (omp_test_nest_lock) 251 252#else 253 254ialias (omp_init_lock) 255ialias (omp_init_nest_lock) 256ialias (omp_destroy_lock) 257ialias (omp_destroy_nest_lock) 258ialias (omp_set_lock) 259ialias (omp_set_nest_lock) 260ialias (omp_unset_lock) 261ialias (omp_unset_nest_lock) 262ialias (omp_test_lock) 263ialias (omp_test_nest_lock) 264 265#endif 266