]> git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/unix/sysv/linux/s390/lowlevellock.h
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / sysdeps / unix / sysv / linux / s390 / lowlevellock.h
1 /* Copyright (C) 2003-2015 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
18
19 #ifndef _LOWLEVELLOCK_H
20 #define _LOWLEVELLOCK_H 1
21
22 #include <time.h>
23 #include <sys/param.h>
24 #include <bits/pthreadtypes.h>
25 #include <atomic.h>
26 #include <kernel-features.h>
27
28 #define SYS_futex 238
29 #define FUTEX_WAIT 0
30 #define FUTEX_WAKE 1
31 #define FUTEX_REQUEUE 3
32 #define FUTEX_CMP_REQUEUE 4
33 #define FUTEX_WAKE_OP 5
34 #define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE ((4 << 24) | 1)
35 #define FUTEX_LOCK_PI 6
36 #define FUTEX_UNLOCK_PI 7
37 #define FUTEX_TRYLOCK_PI 8
38 #define FUTEX_WAIT_BITSET 9
39 #define FUTEX_WAKE_BITSET 10
40 #define FUTEX_WAIT_REQUEUE_PI 11
41 #define FUTEX_CMP_REQUEUE_PI 12
42 #define FUTEX_PRIVATE_FLAG 128
43 #define FUTEX_CLOCK_REALTIME 256
44
45 #define FUTEX_BITSET_MATCH_ANY 0xffffffff
46
47 /* Values for 'private' parameter of locking macros. Yes, the
48 definition seems to be backwards. But it is not. The bit will be
49 reversed before passing to the system call. */
50 #define LLL_PRIVATE 0
51 #define LLL_SHARED FUTEX_PRIVATE_FLAG
52
53
54 #if IS_IN (libc) || IS_IN (rtld)
55 /* In libc.so or ld.so all futexes are private. */
56 # ifdef __ASSUME_PRIVATE_FUTEX
57 # define __lll_private_flag(fl, private) \
58 ((fl) | FUTEX_PRIVATE_FLAG)
59 # else
60 # define __lll_private_flag(fl, private) \
61 ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))
62 # endif
63 #else
64 # ifdef __ASSUME_PRIVATE_FUTEX
65 # define __lll_private_flag(fl, private) \
66 (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
67 # else
68 # define __lll_private_flag(fl, private) \
69 (__builtin_constant_p (private) \
70 ? ((private) == 0 \
71 ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex)) \
72 : (fl)) \
73 : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG) \
74 & THREAD_GETMEM (THREAD_SELF, header.private_futex))))
75 # endif
76 #endif
77
78 #define lll_futex_wait(futex, val, private) \
79 lll_futex_timed_wait (futex, val, NULL, private)
80
81 #define lll_futex_timed_wait(futexp, val, timespec, private) \
82 ({ \
83 INTERNAL_SYSCALL_DECL (__err); \
84 \
85 INTERNAL_SYSCALL (futex, __err, 4, (futexp), \
86 __lll_private_flag (FUTEX_WAIT, private), \
87 (val), (timespec)); \
88 })
89
90 #define lll_futex_timed_wait_bitset(futexp, val, timespec, clockbit, private) \
91 ({ \
92 INTERNAL_SYSCALL_DECL (__err); \
93 int __op = FUTEX_WAIT_BITSET | clockbit; \
94 \
95 INTERNAL_SYSCALL (futex, __err, 6, (futexp), \
96 __lll_private_flag (__op, private), \
97 (val), (timespec), NULL /* Unused. */, \
98 FUTEX_BITSET_MATCH_ANY); \
99 })
100
101 #define lll_futex_wake(futexp, nr, private) \
102 ({ \
103 INTERNAL_SYSCALL_DECL (__err); \
104 \
105 INTERNAL_SYSCALL (futex, __err, 4, (futexp), \
106 __lll_private_flag (FUTEX_WAKE, private), \
107 (nr), 0); \
108 })
109
110
111 /* Returns non-zero if error happened, zero if success. */
112 #define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val, private) \
113 ({ \
114 INTERNAL_SYSCALL_DECL (__err); \
115 long int __ret; \
116 \
117 __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \
118 __lll_private_flag (FUTEX_CMP_REQUEUE, private),\
119 (nr_wake), (nr_move), (mutex), (val)); \
120 INTERNAL_SYSCALL_ERROR_P (__ret, __err); \
121 })
122
123 /* Returns non-zero if error happened, zero if success. */
124 #define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \
125 ({ \
126 INTERNAL_SYSCALL_DECL (__err); \
127 long int __ret; \
128 \
129 __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \
130 __lll_private_flag (FUTEX_WAKE_OP, private), \
131 (nr_wake), (nr_wake2), (futexp2), \
132 FUTEX_OP_CLEAR_WAKE_IF_GT_ONE); \
133 INTERNAL_SYSCALL_ERROR_P (__ret, __err); \
134 })
135
136 /* Priority Inheritance support. */
137 #define lll_futex_wait_requeue_pi(futexp, val, mutex, private) \
138 lll_futex_timed_wait_requeue_pi (futexp, val, NULL, 0, mutex, private)
139
140 #define lll_futex_timed_wait_requeue_pi(futexp, val, timespec, clockbit, \
141 mutex, private) \
142 ({ \
143 INTERNAL_SYSCALL_DECL (__err); \
144 int __op = FUTEX_WAIT_REQUEUE_PI | clockbit; \
145 \
146 INTERNAL_SYSCALL (futex, __err, 5, (futexp), \
147 __lll_private_flag (__op, private), \
148 (val), (timespec), mutex); \
149 })
150
151 #define lll_futex_cmp_requeue_pi(futexp, nr_wake, nr_move, mutex, val, priv) \
152 ({ \
153 INTERNAL_SYSCALL_DECL (__err); \
154 long int __ret; \
155 \
156 __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \
157 __lll_private_flag (FUTEX_CMP_REQUEUE_PI, priv),\
158 (nr_wake), (nr_move), (mutex), (val)); \
159 INTERNAL_SYSCALL_ERROR_P (__ret, __err); \
160 })
161
162 #define lll_compare_and_swap(futex, oldval, newval, operation) \
163 do { \
164 __typeof (futex) __futex = (futex); \
165 __asm __volatile (" l %1,%0\n" \
166 "0: " operation "\n" \
167 " cs %1,%2,%0\n" \
168 " jl 0b\n" \
169 "1:" \
170 : "=Q" (*__futex), "=&d" (oldval), "=&d" (newval) \
171 : "m" (*__futex) : "cc", "memory" ); \
172 } while (0)
173
174
175 static inline int
176 __attribute__ ((always_inline))
177 __lll_trylock (int *futex)
178 {
179 unsigned int old;
180
181 __asm __volatile ("cs %0,%3,%1"
182 : "=d" (old), "=Q" (*futex)
183 : "0" (0), "d" (1), "m" (*futex) : "cc", "memory" );
184 return old != 0;
185 }
186 #define lll_trylock(futex) __lll_trylock (&(futex))
187
188
189 static inline int
190 __attribute__ ((always_inline))
191 __lll_cond_trylock (int *futex)
192 {
193 unsigned int old;
194
195 __asm __volatile ("cs %0,%3,%1"
196 : "=d" (old), "=Q" (*futex)
197 : "0" (0), "d" (2), "m" (*futex) : "cc", "memory" );
198 return old != 0;
199 }
200 #define lll_cond_trylock(futex) __lll_cond_trylock (&(futex))
201
202
203 extern void __lll_lock_wait_private (int *futex) attribute_hidden;
204 extern void __lll_lock_wait (int *futex, int private) attribute_hidden;
205 extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden;
206
207 static inline void
208 __attribute__ ((always_inline))
209 __lll_lock (int *futex, int private)
210 {
211 if (__glibc_unlikely (atomic_compare_and_exchange_bool_acq (futex, 1, 0)))
212 {
213 if (__builtin_constant_p (private) && private == LLL_PRIVATE)
214 __lll_lock_wait_private (futex);
215 else
216 __lll_lock_wait (futex, private);
217 }
218 }
219 #define lll_lock(futex, private) __lll_lock (&(futex), private)
220
221 static inline int
222 __attribute__ ((always_inline))
223 __lll_robust_lock (int *futex, int id, int private)
224 {
225 int result = 0;
226 if (__builtin_expect (atomic_compare_and_exchange_bool_acq (futex, id, 0),
227 0))
228 result = __lll_robust_lock_wait (futex, private);
229 return result;
230 }
231 #define lll_robust_lock(futex, id, private) \
232 __lll_robust_lock (&(futex), id, private)
233
234 static inline void
235 __attribute__ ((always_inline))
236 __lll_cond_lock (int *futex, int private)
237 {
238 if (__glibc_unlikely (atomic_compare_and_exchange_bool_acq (futex, 2, 0)))
239 __lll_lock_wait (futex, private);
240 }
241 #define lll_cond_lock(futex, private) __lll_cond_lock (&(futex), private)
242
243 #define lll_robust_cond_lock(futex, id, private) \
244 __lll_robust_lock (&(futex), (id) | FUTEX_WAITERS, private)
245
246 extern int __lll_timedlock_wait
247 (int *futex, const struct timespec *, int private) attribute_hidden;
248 extern int __lll_robust_timedlock_wait
249 (int *futex, const struct timespec *, int private) attribute_hidden;
250
251 static inline int
252 __attribute__ ((always_inline))
253 __lll_timedlock (int *futex, const struct timespec *abstime, int private)
254 {
255 int result = 0;
256 if (__glibc_unlikely (atomic_compare_and_exchange_bool_acq (futex, 1, 0)))
257 result = __lll_timedlock_wait (futex, abstime, private);
258 return result;
259 }
260 #define lll_timedlock(futex, abstime, private) \
261 __lll_timedlock (&(futex), abstime, private)
262
263 #ifdef ENABLE_LOCK_ELISION
264 extern int __lll_timedlock_elision
265 (int *futex, short *adapt_count, const struct timespec *timeout, int private)
266 attribute_hidden;
267
268 # define lll_timedlock_elision(futex, adapt_count, timeout, private) \
269 __lll_timedlock_elision(&(futex), &(adapt_count), timeout, private)
270 #endif
271
272 static inline int
273 __attribute__ ((always_inline))
274 __lll_robust_timedlock (int *futex, const struct timespec *abstime,
275 int id, int private)
276 {
277 int result = 0;
278 if (__builtin_expect (atomic_compare_and_exchange_bool_acq (futex, id, 0),
279 0))
280 result = __lll_robust_timedlock_wait (futex, abstime, private);
281 return result;
282 }
283 #define lll_robust_timedlock(futex, abstime, id, private) \
284 __lll_robust_timedlock (&(futex), abstime, id, private)
285
286
287 #define __lll_unlock(futex, private) \
288 (void) \
289 ({ int __oldval; \
290 int __newval = 0; \
291 int *__futexp = (futex); \
292 \
293 lll_compare_and_swap (__futexp, __oldval, __newval, "slr %2,%2"); \
294 if (__glibc_unlikely (__oldval > 1)) \
295 lll_futex_wake (__futexp, 1, private); \
296 })
297 #define lll_unlock(futex, private) __lll_unlock(&(futex), private)
298
299
300 #define __lll_robust_unlock(futex, private) \
301 (void) \
302 ({ int __oldval; \
303 int __newval = 0; \
304 int *__futexp = (futex); \
305 \
306 lll_compare_and_swap (__futexp, __oldval, __newval, "slr %2,%2"); \
307 if (__glibc_unlikely (__oldval & FUTEX_WAITERS)) \
308 lll_futex_wake (__futexp, 1, private); \
309 })
310 #define lll_robust_unlock(futex, private) \
311 __lll_robust_unlock(&(futex), private)
312
313 #define lll_islocked(futex) \
314 (futex != 0)
315
316
317 /* Initializers for lock. */
318 #define LLL_LOCK_INITIALIZER (0)
319 #define LLL_LOCK_INITIALIZER_LOCKED (1)
320
321 /* The kernel notifies a process which uses CLONE_CHILD_CLEARTID via futex
322 wakeup when the clone terminates. The memory location contains the
323 thread ID while the clone is running and is reset to zero
324 afterwards. */
325 #define __lll_wait_tid(ptid) \
326 do \
327 { \
328 int __tid; \
329 \
330 while ((__tid = *ptid) != 0) \
331 lll_futex_wait (ptid, __tid, LLL_SHARED); \
332 } \
333 while (0)
334 #define lll_wait_tid(tid) __lll_wait_tid(&(tid))
335
336 extern int __lll_timedwait_tid (int *, const struct timespec *)
337 attribute_hidden;
338
339 #define lll_timedwait_tid(tid, abstime) \
340 ({ \
341 int __res = 0; \
342 if ((tid) != 0) \
343 __res = __lll_timedwait_tid (&(tid), (abstime)); \
344 __res; \
345 })
346
347 #ifdef ENABLE_LOCK_ELISION
348 extern int __lll_lock_elision (int *futex, short *adapt_count, int private)
349 attribute_hidden;
350
351 extern int __lll_unlock_elision(int *futex, int private)
352 attribute_hidden;
353
354 extern int __lll_trylock_elision(int *futex, short *adapt_count)
355 attribute_hidden;
356
357 # define lll_lock_elision(futex, adapt_count, private) \
358 __lll_lock_elision (&(futex), &(adapt_count), private)
359 # define lll_unlock_elision(futex, private) \
360 __lll_unlock_elision (&(futex), private)
361 # define lll_trylock_elision(futex, adapt_count) \
362 __lll_trylock_elision(&(futex), &(adapt_count))
363 #endif
364
365 #endif /* lowlevellock.h */