xref: /netbsd-src/external/gpl3/gcc.old/dist/libgomp/config/linux/lock.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
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 
39 void
40 gomp_init_lock_30 (omp_lock_t *lock)
41 {
42   gomp_mutex_init (lock);
43 }
44 
45 void
46 gomp_destroy_lock_30 (omp_lock_t *lock)
47 {
48   gomp_mutex_destroy (lock);
49 }
50 
51 void
52 gomp_set_lock_30 (omp_lock_t *lock)
53 {
54   gomp_mutex_lock (lock);
55 }
56 
57 void
58 gomp_unset_lock_30 (omp_lock_t *lock)
59 {
60   gomp_mutex_unlock (lock);
61 }
62 
63 int
64 gomp_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 
72 void
73 gomp_init_nest_lock_30 (omp_nest_lock_t *lock)
74 {
75   memset (lock, '\0', sizeof (*lock));
76 }
77 
78 void
79 gomp_destroy_nest_lock_30 (omp_nest_lock_t *lock)
80 {
81 }
82 
83 void
84 gomp_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 
97 void
98 gomp_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 
107 int
108 gomp_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.  */
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)
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)
155 static inline int gomp_tid (void)
156 {
157   return syscall (SYS_gettid);
158 }
159 # elif !defined(__LP64__)
160 static inline int gomp_tid (void)
161 {
162   return (int) gomp_thread ();
163 }
164 # else
165 static __thread int tid_cache;
166 static 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 
176 void
177 gomp_init_nest_lock_25 (omp_nest_lock_25_t *lock)
178 {
179   memset (lock, 0, sizeof (*lock));
180 }
181 
182 void
183 gomp_destroy_nest_lock_25 (omp_nest_lock_25_t *lock)
184 {
185 }
186 
187 void
188 gomp_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 
211 void
212 gomp_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 
223 int
224 gomp_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 
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)
251 
252 #else
253 
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)
264 
265 #endif
266