]> git.ipfire.org Git - thirdparty/gcc.git/blob - libgomp/config/linux/lock.c
* c-cppbuiltin.c (c_cpp_builtins): Change _OPENMP value to
[thirdparty/gcc.git] / libgomp / config / linux / lock.c
1 /* Copyright (C) 2005, 2008 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 Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) 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 Lesser General Public License for
14 more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with libgomp; see the file COPYING.LIB. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301, USA. */
20
21 /* As a special exception, if you link this library with other files, some
22 of which are compiled with GCC, to produce an executable, this library
23 does not by itself cause the resulting executable to be covered by the
24 GNU General Public License. This exception does not however invalidate
25 any other reasons why the executable file might be covered by the GNU
26 General Public License. */
27
28 /* This is a Linux specific implementation of the public OpenMP locking
29 primitives. This implementation uses atomic instructions and the futex
30 syscall. */
31
32 #include <string.h>
33 #include <unistd.h>
34 #include <sys/syscall.h>
35 #include "wait.h"
36
37
38 /* The internal gomp_mutex_t and the external non-recursive omp_lock_t
39 have the same form. Re-use it. */
40
41 void
42 gomp_init_lock_30 (omp_lock_t *lock)
43 {
44 gomp_mutex_init (lock);
45 }
46
47 void
48 gomp_destroy_lock_30 (omp_lock_t *lock)
49 {
50 gomp_mutex_destroy (lock);
51 }
52
53 void
54 gomp_set_lock_30 (omp_lock_t *lock)
55 {
56 gomp_mutex_lock (lock);
57 }
58
59 void
60 gomp_unset_lock_30 (omp_lock_t *lock)
61 {
62 gomp_mutex_unlock (lock);
63 }
64
65 int
66 gomp_test_lock_30 (omp_lock_t *lock)
67 {
68 return __sync_bool_compare_and_swap (lock, 0, 1);
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
111 if (lock->owner == me)
112 return ++lock->count;
113
114 if (__sync_bool_compare_and_swap (&lock->lock, 0, 1))
115 {
116 lock->owner = me;
117 lock->count = 1;
118 return 1;
119 }
120
121 return 0;
122 }
123
124 #ifdef LIBGOMP_GNU_SYMBOL_VERSIONING
125 /* gomp_mutex_* can be safely locked in one thread and
126 unlocked in another thread, so the OpenMP 2.5 and OpenMP 3.0
127 non-nested locks can be the same. */
128 strong_alias (gomp_init_lock_30, gomp_init_lock_25)
129 strong_alias (gomp_destroy_lock_30, gomp_destroy_lock_25)
130 strong_alias (gomp_set_lock_30, gomp_set_lock_25)
131 strong_alias (gomp_unset_lock_30, gomp_unset_lock_25)
132 strong_alias (gomp_test_lock_30, gomp_test_lock_25)
133
134 /* The external recursive omp_nest_lock_25_t form requires additional work. */
135
136 /* We need an integer to uniquely identify this thread. Most generally
137 this is the thread's TID, which ideally we'd get this straight from
138 the TLS block where glibc keeps it. Unfortunately, we can't get at
139 that directly.
140
141 If we don't support (or have disabled) TLS, one function call is as
142 good (or bad) as any other. Use the syscall all the time.
143
144 On an ILP32 system (defined here as not LP64), we can make do with
145 any thread-local pointer. Ideally we'd use the TLS base address,
146 since that requires the least amount of arithmetic, but that's not
147 always available directly. Make do with the gomp_thread pointer
148 since it's handy. */
149
150 # if !defined (HAVE_TLS)
151 static inline int gomp_tid (void)
152 {
153 return syscall (SYS_gettid);
154 }
155 # elif !defined(__LP64__)
156 static inline int gomp_tid (void)
157 {
158 return (int) gomp_thread ();
159 }
160 # else
161 static __thread int tid_cache;
162 static inline int gomp_tid (void)
163 {
164 int tid = tid_cache;
165 if (__builtin_expect (tid == 0, 0))
166 tid_cache = tid = syscall (SYS_gettid);
167 return tid;
168 }
169 # endif
170
171
172 void
173 gomp_init_nest_lock_25 (omp_nest_lock_25_t *lock)
174 {
175 memset (lock, 0, sizeof (lock));
176 }
177
178 void
179 gomp_destroy_nest_lock_25 (omp_nest_lock_25_t *lock)
180 {
181 }
182
183 void
184 gomp_set_nest_lock_25 (omp_nest_lock_25_t *lock)
185 {
186 int otid, tid = gomp_tid ();
187
188 while (1)
189 {
190 otid = __sync_val_compare_and_swap (&lock->owner, 0, tid);
191 if (otid == 0)
192 {
193 lock->count = 1;
194 return;
195 }
196 if (otid == tid)
197 {
198 lock->count++;
199 return;
200 }
201
202 do_wait (&lock->owner, otid);
203 }
204 }
205
206 void
207 gomp_unset_nest_lock_25 (omp_nest_lock_25_t *lock)
208 {
209 /* ??? Validate that we own the lock here. */
210
211 if (--lock->count == 0)
212 {
213 __sync_lock_release (&lock->owner);
214 futex_wake (&lock->owner, 1);
215 }
216 }
217
218 int
219 gomp_test_nest_lock_25 (omp_nest_lock_25_t *lock)
220 {
221 int otid, tid = gomp_tid ();
222
223 otid = __sync_val_compare_and_swap (&lock->owner, 0, tid);
224 if (otid == 0)
225 {
226 lock->count = 1;
227 return 1;
228 }
229 if (otid == tid)
230 return ++lock->count;
231
232 return 0;
233 }
234
235 omp_lock_symver (omp_init_lock)
236 omp_lock_symver (omp_destroy_lock)
237 omp_lock_symver (omp_set_lock)
238 omp_lock_symver (omp_unset_lock)
239 omp_lock_symver (omp_test_lock)
240 omp_lock_symver (omp_init_nest_lock)
241 omp_lock_symver (omp_destroy_nest_lock)
242 omp_lock_symver (omp_set_nest_lock)
243 omp_lock_symver (omp_unset_nest_lock)
244 omp_lock_symver (omp_test_nest_lock)
245
246 #else
247
248 ialias (omp_init_lock)
249 ialias (omp_init_nest_lock)
250 ialias (omp_destroy_lock)
251 ialias (omp_destroy_nest_lock)
252 ialias (omp_set_lock)
253 ialias (omp_set_nest_lock)
254 ialias (omp_unset_lock)
255 ialias (omp_unset_nest_lock)
256 ialias (omp_test_lock)
257 ialias (omp_test_nest_lock)
258
259 #endif