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