1 /* Copyright (C) 2005-2015 Free Software Foundation, Inc.
2 Contributed by Richard Henderson <rth@redhat.com>.
4 This file is part of the GNU Offloading and Multi Processing Library
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)
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
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.
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/>. */
26 /* This is a Linux specific implementation of the public OpenMP locking
27 primitives. This implementation uses atomic instructions and the futex
32 #include <sys/syscall.h>
36 /* The internal gomp_mutex_t and the external non-recursive omp_lock_t
37 have the same form. Re-use it. */
40 gomp_init_lock_30 (omp_lock_t
*lock
)
42 gomp_mutex_init (lock
);
46 gomp_destroy_lock_30 (omp_lock_t
*lock
)
48 gomp_mutex_destroy (lock
);
52 gomp_set_lock_30 (omp_lock_t
*lock
)
54 gomp_mutex_lock (lock
);
58 gomp_unset_lock_30 (omp_lock_t
*lock
)
60 gomp_mutex_unlock (lock
);
64 gomp_test_lock_30 (omp_lock_t
*lock
)
68 return __atomic_compare_exchange_n (lock
, &oldval
, 1, false,
69 MEMMODEL_ACQUIRE
, MEMMODEL_RELAXED
);
73 gomp_init_nest_lock_30 (omp_nest_lock_t
*lock
)
75 memset (lock
, '\0', sizeof (*lock
));
79 gomp_destroy_nest_lock_30 (omp_nest_lock_t
*lock
)
84 gomp_set_nest_lock_30 (omp_nest_lock_t
*lock
)
86 void *me
= gomp_icv (true);
88 if (lock
->owner
!= me
)
90 gomp_mutex_lock (&lock
->lock
);
98 gomp_unset_nest_lock_30 (omp_nest_lock_t
*lock
)
100 if (--lock
->count
== 0)
103 gomp_mutex_unlock (&lock
->lock
);
108 gomp_test_nest_lock_30 (omp_nest_lock_t
*lock
)
110 void *me
= gomp_icv (true);
113 if (lock
->owner
== me
)
114 return ++lock
->count
;
117 if (__atomic_compare_exchange_n (&lock
->lock
, &oldval
, 1, false,
118 MEMMODEL_ACQUIRE
, MEMMODEL_RELAXED
))
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. */
132 strong_alias (gomp_init_lock_30
, gomp_init_lock_25
)
133 strong_alias (gomp_destroy_lock_30
, gomp_destroy_lock_25
)
134 strong_alias (gomp_set_lock_30
, gomp_set_lock_25
)
135 strong_alias (gomp_unset_lock_30
, gomp_unset_lock_25
)
136 strong_alias (gomp_test_lock_30
, gomp_test_lock_25
)
138 /* The external recursive omp_nest_lock_25_t form requires additional work. */
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
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.
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
154 # if !defined (HAVE_TLS)
155 static inline int gomp_tid (void)
157 return syscall (SYS_gettid
);
159 # elif !defined(__LP64__)
160 static inline int gomp_tid (void)
162 return (int) gomp_thread ();
165 static __thread
int tid_cache
;
166 static inline int gomp_tid (void)
169 if (__builtin_expect (tid
== 0, 0))
170 tid_cache
= tid
= syscall (SYS_gettid
);
177 gomp_init_nest_lock_25 (omp_nest_lock_25_t
*lock
)
179 memset (lock
, 0, sizeof (*lock
));
183 gomp_destroy_nest_lock_25 (omp_nest_lock_25_t
*lock
)
188 gomp_set_nest_lock_25 (omp_nest_lock_25_t
*lock
)
190 int otid
, tid
= gomp_tid ();
195 if (__atomic_compare_exchange_n (&lock
->owner
, &otid
, tid
, false,
196 MEMMODEL_ACQUIRE
, MEMMODEL_RELAXED
))
207 do_wait (&lock
->owner
, otid
);
212 gomp_unset_nest_lock_25 (omp_nest_lock_25_t
*lock
)
214 /* ??? Validate that we own the lock here. */
216 if (--lock
->count
== 0)
218 __atomic_store_n (&lock
->owner
, 0, MEMMODEL_RELEASE
);
219 futex_wake (&lock
->owner
, 1);
224 gomp_test_nest_lock_25 (omp_nest_lock_25_t
*lock
)
226 int otid
, tid
= gomp_tid ();
229 if (__atomic_compare_exchange_n (&lock
->owner
, &otid
, tid
, false,
230 MEMMODEL_ACQUIRE
, MEMMODEL_RELAXED
))
236 return ++lock
->count
;
241 omp_lock_symver (omp_init_lock
)
242 omp_lock_symver (omp_destroy_lock
)
243 omp_lock_symver (omp_set_lock
)
244 omp_lock_symver (omp_unset_lock
)
245 omp_lock_symver (omp_test_lock
)
246 omp_lock_symver (omp_init_nest_lock
)
247 omp_lock_symver (omp_destroy_nest_lock
)
248 omp_lock_symver (omp_set_nest_lock
)
249 omp_lock_symver (omp_unset_nest_lock
)
250 omp_lock_symver (omp_test_nest_lock
)
254 ialias (omp_init_lock
)
255 ialias (omp_init_nest_lock
)
256 ialias (omp_destroy_lock
)
257 ialias (omp_destroy_nest_lock
)
258 ialias (omp_set_lock
)
259 ialias (omp_set_nest_lock
)
260 ialias (omp_unset_lock
)
261 ialias (omp_unset_nest_lock
)
262 ialias (omp_test_lock
)
263 ialias (omp_test_nest_lock
)