OSDN Git Service

Backported from mainline
[pf3gnuchains/gcc-fork.git] / libgomp / config / linux / lock.c
1 /* Copyright (C) 2005, 2008, 2009, 2011, 2012 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