]> git.ipfire.org Git - thirdparty/gcc.git/blob - libgomp/config/linux/lock.c
Update copyright years.
[thirdparty/gcc.git] / libgomp / config / linux / lock.c
1 /* Copyright (C) 2005-2023 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 /* Reuse the generic implementation in terms of gomp_mutex_t. */
36 #include "../../lock.c"
37
38 #ifdef LIBGOMP_GNU_SYMBOL_VERSIONING
39 /* gomp_mutex_* can be safely locked in one thread and
40 unlocked in another thread, so the OpenMP 2.5 and OpenMP 3.0
41 non-nested locks can be the same. */
42 strong_alias (gomp_init_lock_30, gomp_init_lock_25)
43 strong_alias (gomp_destroy_lock_30, gomp_destroy_lock_25)
44 strong_alias (gomp_set_lock_30, gomp_set_lock_25)
45 strong_alias (gomp_unset_lock_30, gomp_unset_lock_25)
46 strong_alias (gomp_test_lock_30, gomp_test_lock_25)
47
48 /* The external recursive omp_nest_lock_25_t form requires additional work. */
49
50 /* We need an integer to uniquely identify this thread. Most generally
51 this is the thread's TID, which ideally we'd get this straight from
52 the TLS block where glibc keeps it. Unfortunately, we can't get at
53 that directly.
54
55 If we don't support (or have disabled) TLS, one function call is as
56 good (or bad) as any other. Use the syscall all the time.
57
58 On an ILP32 system (defined here as not LP64), we can make do with
59 any thread-local pointer. Ideally we'd use the TLS base address,
60 since that requires the least amount of arithmetic, but that's not
61 always available directly. Make do with the gomp_thread pointer
62 since it's handy. */
63
64 # if !defined (HAVE_TLS)
65 static inline int gomp_tid (void)
66 {
67 return syscall (SYS_gettid);
68 }
69 # elif !defined(__LP64__)
70 static inline int gomp_tid (void)
71 {
72 return (int) gomp_thread ();
73 }
74 # else
75 static __thread int tid_cache;
76 static inline int gomp_tid (void)
77 {
78 int tid = tid_cache;
79 if (__builtin_expect (tid == 0, 0))
80 tid_cache = tid = syscall (SYS_gettid);
81 return tid;
82 }
83 # endif
84
85
86 void
87 gomp_init_nest_lock_25 (omp_nest_lock_25_t *lock)
88 {
89 memset (lock, 0, sizeof (*lock));
90 }
91
92 void
93 gomp_destroy_nest_lock_25 (omp_nest_lock_25_t *lock)
94 {
95 }
96
97 void
98 gomp_set_nest_lock_25 (omp_nest_lock_25_t *lock)
99 {
100 int otid, tid = gomp_tid ();
101
102 while (1)
103 {
104 otid = 0;
105 if (__atomic_compare_exchange_n (&lock->owner, &otid, tid, false,
106 MEMMODEL_ACQUIRE, MEMMODEL_RELAXED))
107 {
108 lock->count = 1;
109 return;
110 }
111 if (otid == tid)
112 {
113 lock->count++;
114 return;
115 }
116
117 do_wait (&lock->owner, otid);
118 }
119 }
120
121 void
122 gomp_unset_nest_lock_25 (omp_nest_lock_25_t *lock)
123 {
124 /* ??? Validate that we own the lock here. */
125
126 if (--lock->count == 0)
127 {
128 __atomic_store_n (&lock->owner, 0, MEMMODEL_RELEASE);
129 futex_wake (&lock->owner, 1);
130 }
131 }
132
133 int
134 gomp_test_nest_lock_25 (omp_nest_lock_25_t *lock)
135 {
136 int otid, tid = gomp_tid ();
137
138 otid = 0;
139 if (__atomic_compare_exchange_n (&lock->owner, &otid, tid, false,
140 MEMMODEL_ACQUIRE, MEMMODEL_RELAXED))
141 {
142 lock->count = 1;
143 return 1;
144 }
145 if (otid == tid)
146 return ++lock->count;
147
148 return 0;
149 }
150
151 omp_lock_symver (omp_init_lock)
152 omp_lock_symver (omp_destroy_lock)
153 omp_lock_symver (omp_set_lock)
154 omp_lock_symver (omp_unset_lock)
155 omp_lock_symver (omp_test_lock)
156 omp_lock_symver (omp_init_nest_lock)
157 omp_lock_symver (omp_destroy_nest_lock)
158 omp_lock_symver (omp_set_nest_lock)
159 omp_lock_symver (omp_unset_nest_lock)
160 omp_lock_symver (omp_test_nest_lock)
161
162 #else
163
164 ialias (omp_init_lock)
165 ialias (omp_init_nest_lock)
166 ialias (omp_destroy_lock)
167 ialias (omp_destroy_nest_lock)
168 ialias (omp_set_lock)
169 ialias (omp_set_nest_lock)
170 ialias (omp_unset_lock)
171 ialias (omp_unset_nest_lock)
172 ialias (omp_test_lock)
173 ialias (omp_test_nest_lock)
174
175 #endif