2.9
[glibc/nacl-glibc.git] / nptl / sysdeps / unix / sysv / linux / s390 / lowlevellock.h
blobc9347e98b24fffb0e8f4824acbd19adef41d547a
1 /* Copyright (C) 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
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.
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.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
20 #ifndef _LOWLEVELLOCK_H
21 #define _LOWLEVELLOCK_H 1
23 #include <time.h>
24 #include <sys/param.h>
25 #include <bits/pthreadtypes.h>
26 #include <atomic.h>
27 #include <kernel-features.h>
29 #define SYS_futex 238
30 #define FUTEX_WAIT 0
31 #define FUTEX_WAKE 1
32 #define FUTEX_REQUEUE 3
33 #define FUTEX_CMP_REQUEUE 4
34 #define FUTEX_WAKE_OP 5
35 #define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE ((4 << 24) | 1)
36 #define FUTEX_LOCK_PI 6
37 #define FUTEX_UNLOCK_PI 7
38 #define FUTEX_TRYLOCK_PI 8
39 #define FUTEX_PRIVATE_FLAG 128
41 /* Values for 'private' parameter of locking macros. Yes, the
42 definition seems to be backwards. But it is not. The bit will be
43 reversed before passing to the system call. */
44 #define LLL_PRIVATE 0
45 #define LLL_SHARED FUTEX_PRIVATE_FLAG
48 #if !defined NOT_IN_libc || defined IS_IN_rtld
49 /* In libc.so or ld.so all futexes are private. */
50 # ifdef __ASSUME_PRIVATE_FUTEX
51 # define __lll_private_flag(fl, private) \
52 ((fl) | FUTEX_PRIVATE_FLAG)
53 # else
54 # define __lll_private_flag(fl, private) \
55 ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))
56 # endif
57 #else
58 # ifdef __ASSUME_PRIVATE_FUTEX
59 # define __lll_private_flag(fl, private) \
60 (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
61 # else
62 # define __lll_private_flag(fl, private) \
63 (__builtin_constant_p (private) \
64 ? ((private) == 0 \
65 ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex)) \
66 : (fl)) \
67 : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG) \
68 & THREAD_GETMEM (THREAD_SELF, header.private_futex))))
69 # endif
70 #endif
72 #define lll_futex_wait(futex, val, private) \
73 lll_futex_timed_wait (futex, val, NULL, private)
75 #define lll_futex_timed_wait(futex, val, timespec, private) \
76 ({ \
77 register unsigned long int __r2 asm ("2") = (unsigned long int) (futex); \
78 register unsigned long int __r3 asm ("3") \
79 = __lll_private_flag (FUTEX_WAIT, private); \
80 register unsigned long int __r4 asm ("4") = (unsigned long int) (val); \
81 register unsigned long int __r5 asm ("5") = (unsigned long int)(timespec);\
82 register unsigned long int __result asm ("2"); \
84 __asm __volatile ("svc %b1" \
85 : "=d" (__result) \
86 : "i" (SYS_futex), "0" (__r2), "d" (__r3), \
87 "d" (__r4), "d" (__r5) \
88 : "cc", "memory" ); \
89 __result; \
93 #define lll_futex_wake(futex, nr, private) \
94 ({ \
95 register unsigned long int __r2 asm ("2") = (unsigned long int) (futex); \
96 register unsigned long int __r3 asm ("3") \
97 = __lll_private_flag (FUTEX_WAKE, private); \
98 register unsigned long int __r4 asm ("4") = (unsigned long int) (nr); \
99 register unsigned long int __result asm ("2"); \
101 __asm __volatile ("svc %b1" \
102 : "=d" (__result) \
103 : "i" (SYS_futex), "0" (__r2), "d" (__r3), "d" (__r4) \
104 : "cc", "memory" ); \
105 __result; \
109 #define lll_robust_dead(futexv, private) \
110 do \
112 int *__futexp = &(futexv); \
114 atomic_or (__futexp, FUTEX_OWNER_DIED); \
115 lll_futex_wake (__futexp, 1, private); \
117 while (0)
120 /* Returns non-zero if error happened, zero if success. */
121 #define lll_futex_requeue(futex, nr_wake, nr_move, mutex, val, private) \
122 ({ \
123 register unsigned long int __r2 asm ("2") = (unsigned long int) (futex); \
124 register unsigned long int __r3 asm ("3") \
125 = __lll_private_flag (FUTEX_CMP_REQUEUE, private); \
126 register unsigned long int __r4 asm ("4") = (long int) (nr_wake); \
127 register unsigned long int __r5 asm ("5") = (long int) (nr_move); \
128 register unsigned long int __r6 asm ("6") = (unsigned long int) (mutex); \
129 register unsigned long int __r7 asm ("7") = (int) (val); \
130 register unsigned long __result asm ("2"); \
132 __asm __volatile ("svc %b1" \
133 : "=d" (__result) \
134 : "i" (SYS_futex), "0" (__r2), "d" (__r3), \
135 "d" (__r4), "d" (__r5), "d" (__r6), "d" (__r7) \
136 : "cc", "memory" ); \
137 __result > -4096UL; \
141 /* Returns non-zero if error happened, zero if success. */
142 #define lll_futex_wake_unlock(futex, nr_wake, nr_wake2, futex2, private) \
143 ({ \
144 register unsigned long int __r2 asm ("2") = (unsigned long int) (futex); \
145 register unsigned long int __r3 asm ("3") \
146 = __lll_private_flag (FUTEX_WAKE_OP, private); \
147 register unsigned long int __r4 asm ("4") = (long int) (nr_wake); \
148 register unsigned long int __r5 asm ("5") = (long int) (nr_wake2); \
149 register unsigned long int __r6 asm ("6") = (unsigned long int) (futex2); \
150 register unsigned long int __r7 asm ("7") \
151 = (int) FUTEX_OP_CLEAR_WAKE_IF_GT_ONE; \
152 register unsigned long __result asm ("2"); \
154 __asm __volatile ("svc %b1" \
155 : "=d" (__result) \
156 : "i" (SYS_futex), "0" (__r2), "d" (__r3), \
157 "d" (__r4), "d" (__r5), "d" (__r6), "d" (__r7) \
158 : "cc", "memory" ); \
159 __result > -4096UL; \
163 #define lll_compare_and_swap(futex, oldval, newval, operation) \
164 do { \
165 __typeof (futex) __futex = (futex); \
166 __asm __volatile (" l %1,%0\n" \
167 "0: " operation "\n" \
168 " cs %1,%2,%0\n" \
169 " jl 0b\n" \
170 "1:" \
171 : "=Q" (*__futex), "=&d" (oldval), "=&d" (newval) \
172 : "m" (*__futex) : "cc", "memory" ); \
173 } while (0)
176 static inline int
177 __attribute__ ((always_inline))
178 __lll_trylock (int *futex)
180 unsigned int old;
182 __asm __volatile ("cs %0,%3,%1"
183 : "=d" (old), "=Q" (*futex)
184 : "0" (0), "d" (1), "m" (*futex) : "cc", "memory" );
185 return old != 0;
187 #define lll_trylock(futex) __lll_trylock (&(futex))
190 static inline int
191 __attribute__ ((always_inline))
192 __lll_cond_trylock (int *futex)
194 unsigned int old;
196 __asm __volatile ("cs %0,%3,%1"
197 : "=d" (old), "=Q" (*futex)
198 : "0" (0), "d" (2), "m" (*futex) : "cc", "memory" );
199 return old != 0;
201 #define lll_cond_trylock(futex) __lll_cond_trylock (&(futex))
204 static inline int
205 __attribute__ ((always_inline))
206 __lll_robust_trylock (int *futex, int id)
208 unsigned int old;
210 __asm __volatile ("cs %0,%3,%1"
211 : "=d" (old), "=Q" (*futex)
212 : "0" (0), "d" (id), "m" (*futex) : "cc", "memory" );
213 return old != 0;
215 #define lll_robust_trylock(futex, id) \
216 __lll_robust_trylock (&(futex), id)
219 extern void __lll_lock_wait_private (int *futex) attribute_hidden;
220 extern void __lll_lock_wait (int *futex, int private) attribute_hidden;
221 extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden;
223 static inline void
224 __attribute__ ((always_inline))
225 __lll_lock (int *futex, int private)
227 if (__builtin_expect (atomic_compare_and_exchange_bool_acq (futex, 1, 0), 0))
229 if (__builtin_constant_p (private) && private == LLL_PRIVATE)
230 __lll_lock_wait_private (futex);
231 else
232 __lll_lock_wait (futex, private);
235 #define lll_lock(futex, private) __lll_lock (&(futex), private)
237 static inline int
238 __attribute__ ((always_inline))
239 __lll_robust_lock (int *futex, int id, int private)
241 int result = 0;
242 if (__builtin_expect (atomic_compare_and_exchange_bool_acq (futex, id, 0),
244 result = __lll_robust_lock_wait (futex, private);
245 return result;
247 #define lll_robust_lock(futex, id, private) \
248 __lll_robust_lock (&(futex), id, private)
250 static inline void
251 __attribute__ ((always_inline))
252 __lll_cond_lock (int *futex, int private)
254 if (__builtin_expect (atomic_compare_and_exchange_bool_acq (futex, 2, 0), 0))
255 __lll_lock_wait (futex, private);
257 #define lll_cond_lock(futex, private) __lll_cond_lock (&(futex), private)
259 #define lll_robust_cond_lock(futex, id, private) \
260 __lll_robust_lock (&(futex), (id) | FUTEX_WAITERS, private)
262 extern int __lll_timedlock_wait
263 (int *futex, const struct timespec *, int private) attribute_hidden;
264 extern int __lll_robust_timedlock_wait
265 (int *futex, const struct timespec *, int private) attribute_hidden;
267 static inline int
268 __attribute__ ((always_inline))
269 __lll_timedlock (int *futex, const struct timespec *abstime, int private)
271 int result = 0;
272 if (__builtin_expect (atomic_compare_and_exchange_bool_acq (futex, 1, 0), 0))
273 result = __lll_timedlock_wait (futex, abstime, private);
274 return result;
276 #define lll_timedlock(futex, abstime, private) \
277 __lll_timedlock (&(futex), abstime, private)
279 static inline int
280 __attribute__ ((always_inline))
281 __lll_robust_timedlock (int *futex, const struct timespec *abstime,
282 int id, int private)
284 int result = 0;
285 if (__builtin_expect (atomic_compare_and_exchange_bool_acq (futex, id, 0),
287 result = __lll_robust_timedlock_wait (futex, abstime, private);
288 return result;
290 #define lll_robust_timedlock(futex, abstime, id, private) \
291 __lll_robust_timedlock (&(futex), abstime, id, private)
294 #define __lll_unlock(futex, private) \
295 (void) \
296 ({ int __oldval; \
297 int __newval = 0; \
298 int *__futexp = (futex); \
300 lll_compare_and_swap (__futexp, __oldval, __newval, "slr %2,%2"); \
301 if (__builtin_expect (__oldval > 1, 0)) \
302 lll_futex_wake (__futexp, 1, private); \
304 #define lll_unlock(futex, private) __lll_unlock(&(futex), private)
307 #define __lll_robust_unlock(futex, private) \
308 (void) \
309 ({ int __oldval; \
310 int __newval = 0; \
311 int *__futexp = (futex); \
313 lll_compare_and_swap (__futexp, __oldval, __newval, "slr %2,%2"); \
314 if (__builtin_expect (__oldval & FUTEX_WAITERS, 0)) \
315 lll_futex_wake (__futexp, 1, private); \
317 #define lll_robust_unlock(futex, private) \
318 __lll_robust_unlock(&(futex), private)
320 #define lll_islocked(futex) \
321 (futex != 0)
324 /* Initializers for lock. */
325 #define LLL_LOCK_INITIALIZER (0)
326 #define LLL_LOCK_INITIALIZER_LOCKED (1)
328 /* The kernel notifies a process with uses CLONE_CLEARTID via futex
329 wakeup when the clone terminates. The memory location contains the
330 thread ID while the clone is running and is reset to zero
331 afterwards. */
332 #define __lll_wait_tid(ptid) \
333 do \
335 int __tid; \
337 while ((__tid = *ptid) != 0) \
338 lll_futex_wait (ptid, __tid, LLL_SHARED); \
340 while (0)
341 #define lll_wait_tid(tid) __lll_wait_tid(&(tid))
343 extern int __lll_timedwait_tid (int *, const struct timespec *)
344 attribute_hidden;
346 #define lll_timedwait_tid(tid, abstime) \
347 ({ \
348 int __res = 0; \
349 if ((tid) != 0) \
350 __res = __lll_timedwait_tid (&(tid), (abstime)); \
351 __res; \
354 #endif /* lowlevellock.h */