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
20 #ifndef _LOWLEVELLOCK_H
21 #define _LOWLEVELLOCK_H 1
24 #include <sys/param.h>
25 #include <bits/pthreadtypes.h>
27 #include <kernel-features.h>
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. */
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)
54 # define __lll_private_flag(fl, private) \
55 ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))
58 # ifdef __ASSUME_PRIVATE_FUTEX
59 # define __lll_private_flag(fl, private) \
60 (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
62 # define __lll_private_flag(fl, private) \
63 (__builtin_constant_p (private) \
65 ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex)) \
67 : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG) \
68 & THREAD_GETMEM (THREAD_SELF, header.private_futex))))
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) \
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" \
86 : "i" (SYS_futex), "0" (__r2), "d" (__r3), \
87 "d" (__r4), "d" (__r5) \
93 #define lll_futex_wake(futex, nr, private) \
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" \
103 : "i" (SYS_futex), "0" (__r2), "d" (__r3), "d" (__r4) \
104 : "cc", "memory" ); \
109 #define lll_robust_dead(futexv, private) \
112 int *__futexp = &(futexv); \
114 atomic_or (__futexp, FUTEX_OWNER_DIED); \
115 lll_futex_wake (__futexp, 1, private); \
120 /* Returns non-zero if error happened, zero if success. */
121 #define lll_futex_requeue(futex, nr_wake, nr_move, mutex, val, private) \
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" \
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) \
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" \
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) \
165 __typeof (futex) __futex = (futex); \
166 __asm __volatile (" l %1,%0\n" \
167 "0: " operation "\n" \
171 : "=Q" (*__futex), "=&d" (oldval), "=&d" (newval) \
172 : "m" (*__futex) : "cc", "memory" ); \
177 __attribute__ ((always_inline
))
178 __lll_trylock (int *futex
)
182 __asm
__volatile ("cs %0,%3,%1"
183 : "=d" (old
), "=Q" (*futex
)
184 : "0" (0), "d" (1), "m" (*futex
) : "cc", "memory" );
187 #define lll_trylock(futex) __lll_trylock (&(futex))
191 __attribute__ ((always_inline
))
192 __lll_cond_trylock (int *futex
)
196 __asm
__volatile ("cs %0,%3,%1"
197 : "=d" (old
), "=Q" (*futex
)
198 : "0" (0), "d" (2), "m" (*futex
) : "cc", "memory" );
201 #define lll_cond_trylock(futex) __lll_cond_trylock (&(futex))
205 __attribute__ ((always_inline
))
206 __lll_robust_trylock (int *futex
, int id
)
210 __asm
__volatile ("cs %0,%3,%1"
211 : "=d" (old
), "=Q" (*futex
)
212 : "0" (0), "d" (id
), "m" (*futex
) : "cc", "memory" );
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
;
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
);
232 __lll_lock_wait (futex
, private);
235 #define lll_lock(futex, private) __lll_lock (&(futex), private)
238 __attribute__ ((always_inline
))
239 __lll_robust_lock (int *futex
, int id
, int private)
242 if (__builtin_expect (atomic_compare_and_exchange_bool_acq (futex
, id
, 0),
244 result
= __lll_robust_lock_wait (futex
, private);
247 #define lll_robust_lock(futex, id, private) \
248 __lll_robust_lock (&(futex), id, private)
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
;
268 __attribute__ ((always_inline
))
269 __lll_timedlock (int *futex
, const struct timespec
*abstime
, int private)
272 if (__builtin_expect (atomic_compare_and_exchange_bool_acq (futex
, 1, 0), 0))
273 result
= __lll_timedlock_wait (futex
, abstime
, private);
276 #define lll_timedlock(futex, abstime, private) \
277 __lll_timedlock (&(futex), abstime, private)
280 __attribute__ ((always_inline
))
281 __lll_robust_timedlock (int *futex
, const struct timespec
*abstime
,
285 if (__builtin_expect (atomic_compare_and_exchange_bool_acq (futex
, id
, 0),
287 result
= __lll_robust_timedlock_wait (futex
, abstime
, private);
290 #define lll_robust_timedlock(futex, abstime, id, private) \
291 __lll_robust_timedlock (&(futex), abstime, id, private)
294 #define __lll_unlock(futex, private) \
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) \
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) \
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
332 #define __lll_wait_tid(ptid) \
337 while ((__tid = *ptid) != 0) \
338 lll_futex_wait (ptid, __tid, LLL_SHARED); \
341 #define lll_wait_tid(tid) __lll_wait_tid(&(tid))
343 extern int __lll_timedwait_tid (int *, const struct timespec
*)
346 #define lll_timedwait_tid(tid, abstime) \
350 __res = __lll_timedwait_tid (&(tid), (abstime)); \
354 #endif /* lowlevellock.h */