]> git.ipfire.org Git - thirdparty/glibc.git/blame - nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h
Add bug 14805 to list of fixed bugs in NEWS.
[thirdparty/glibc.git] / nptl / sysdeps / unix / sysv / linux / powerpc / lowlevellock.h
CommitLineData
7dd650d7 1/* Copyright (C) 2003, 2004, 2006-2008, 2009 Free Software Foundation, Inc.
f3c13160
RM
2 This file is part of the GNU C Library.
3 Contributed by Paul Mackerras <paulus@au.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
59ba27a6
PE
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
f3c13160
RM
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>
b1aea098 25#include <atomic.h>
f8de5057 26#include <kernel-features.h>
b1aea098 27
ce6e047f
UD
28#ifndef __NR_futex
29# define __NR_futex 221
30#endif
f3c13160
RM
31#define FUTEX_WAIT 0
32#define FUTEX_WAKE 1
b8ba4a27 33#define FUTEX_REQUEUE 3
75fccede 34#define FUTEX_CMP_REQUEUE 4
b9b8cf03
UD
35#define FUTEX_WAKE_OP 5
36#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE ((4 << 24) | 1)
d5ba53f9
UD
37#define FUTEX_LOCK_PI 6
38#define FUTEX_UNLOCK_PI 7
39#define FUTEX_TRYLOCK_PI 8
da5ac135
UD
40#define FUTEX_WAIT_BITSET 9
41#define FUTEX_WAKE_BITSET 10
e59660bc 42#define FUTEX_PRIVATE_FLAG 128
7dd650d7
UD
43#define FUTEX_CLOCK_REALTIME 256
44
45#define FUTEX_BITSET_MATCH_ANY 0xffffffff
e59660bc 46
eb7721f2
UD
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
b5f13526
UD
53#if !defined NOT_IN_libc || defined IS_IN_rtld
54/* In libc.so or ld.so all futexes are private. */
55# ifdef __ASSUME_PRIVATE_FUTEX
56# define __lll_private_flag(fl, private) \
57 ((fl) | FUTEX_PRIVATE_FLAG)
58# else
59# define __lll_private_flag(fl, private) \
60 ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))
61# endif
62#else
63# ifdef __ASSUME_PRIVATE_FUTEX
64# define __lll_private_flag(fl, private) \
65 (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
66# else
67# define __lll_private_flag(fl, private) \
68 (__builtin_constant_p (private) \
69 ? ((private) == 0 \
70 ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex)) \
71 : (fl)) \
72 : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG) \
73 & THREAD_GETMEM (THREAD_SELF, header.private_futex))))
da5ac135 74# endif
b5f13526 75#endif
f3c13160 76
eb7721f2 77#define lll_futex_wait(futexp, val, private) \
b5f13526 78 lll_futex_timed_wait (futexp, val, NULL, private)
f3c13160 79
eb7721f2 80#define lll_futex_timed_wait(futexp, val, timespec, private) \
bd0fa4ce
UD
81 ({ \
82 INTERNAL_SYSCALL_DECL (__err); \
83 long int __ret; \
84 \
b5f13526
UD
85 __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp), \
86 __lll_private_flag (FUTEX_WAIT, private), \
87 (val), (timespec)); \
9bdabb94 88 INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret; \
f3c13160
RM
89 })
90
eb7721f2 91#define lll_futex_wake(futexp, nr, private) \
bd0fa4ce
UD
92 ({ \
93 INTERNAL_SYSCALL_DECL (__err); \
94 long int __ret; \
95 \
b5f13526
UD
96 __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp), \
97 __lll_private_flag (FUTEX_WAKE, private), \
98 (nr), 0); \
9bdabb94 99 INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret; \
f3c13160
RM
100 })
101
e51deae7 102#define lll_robust_dead(futexv, private) \
f1740bc4
UD
103 do \
104 { \
105 INTERNAL_SYSCALL_DECL (__err); \
106 int *__futexp = &(futexv); \
107 \
108 atomic_or (__futexp, FUTEX_OWNER_DIED); \
e51deae7
UD
109 INTERNAL_SYSCALL (futex, __err, 4, __futexp, \
110 __lll_private_flag (FUTEX_WAKE, private), 1, 0); \
f1740bc4
UD
111 } \
112 while (0)
113
75fccede 114/* Returns non-zero if error happened, zero if success. */
5bd8a249 115#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val, private) \
b8ba4a27
UD
116 ({ \
117 INTERNAL_SYSCALL_DECL (__err); \
118 long int __ret; \
119 \
5bd8a249
UD
120 __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \
121 __lll_private_flag (FUTEX_CMP_REQUEUE, private),\
122 (nr_wake), (nr_move), (mutex), (val)); \
75fccede 123 INTERNAL_SYSCALL_ERROR_P (__ret, __err); \
b8ba4a27
UD
124 })
125
b9b8cf03 126/* Returns non-zero if error happened, zero if success. */
eb7721f2 127#define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \
b9b8cf03
UD
128 ({ \
129 INTERNAL_SYSCALL_DECL (__err); \
130 long int __ret; \
131 \
b5f13526
UD
132 __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \
133 __lll_private_flag (FUTEX_WAKE_OP, private), \
134 (nr_wake), (nr_wake2), (futexp2), \
135 FUTEX_OP_CLEAR_WAKE_IF_GT_ONE); \
b9b8cf03
UD
136 INTERNAL_SYSCALL_ERROR_P (__ret, __err); \
137 })
da5ac135
UD
138
139
f3c13160 140#ifdef UP
bd0fa4ce
UD
141# define __lll_acq_instr ""
142# define __lll_rel_instr ""
f3c13160 143#else
bd0fa4ce 144# define __lll_acq_instr "isync"
f9d35bb9
RM
145# ifdef _ARCH_PWR4
146/*
147 * Newer powerpc64 processors support the new "light weight" sync (lwsync)
148 * So if the build is using -mcpu=[power4,power5,power5+,970] we can
149 * safely use lwsync.
150 */
151# define __lll_rel_instr "lwsync"
152# else
153/*
154 * Older powerpc32 processors don't support the new "light weight"
155 * sync (lwsync). So the only safe option is to use normal sync
156 * for all powerpc32 applications.
157 */
158# define __lll_rel_instr "sync"
159# endif
f3c13160
RM
160#endif
161
f1740bc4
UD
162/* Set *futex to ID if it is 0, atomically. Returns the old value */
163#define __lll_robust_trylock(futex, id) \
bd0fa4ce 164 ({ int __val; \
fa6e3bc3 165 __asm __volatile ("1: lwarx %0,0,%2" MUTEX_HINT_ACQ "\n" \
bd0fa4ce
UD
166 " cmpwi 0,%0,0\n" \
167 " bne 2f\n" \
168 " stwcx. %3,0,%2\n" \
169 " bne- 1b\n" \
170 "2: " __lll_acq_instr \
171 : "=&r" (__val), "=m" (*futex) \
f1740bc4 172 : "r" (futex), "r" (id), "m" (*futex) \
bd0fa4ce
UD
173 : "cr0", "memory"); \
174 __val; \
f3c13160
RM
175 })
176
e51deae7 177#define lll_robust_trylock(lock, id) __lll_robust_trylock (&(lock), id)
f1740bc4
UD
178
179/* Set *futex to 1 if it is 0, atomically. Returns the old value */
180#define __lll_trylock(futex) __lll_robust_trylock (futex, 1)
181
e51deae7 182#define lll_trylock(lock) __lll_trylock (&(lock))
043ad426 183
2c0b891a 184/* Set *futex to 2 if it is 0, atomically. Returns the old value */
f1740bc4
UD
185#define __lll_cond_trylock(futex) __lll_robust_trylock (futex, 2)
186
e51deae7 187#define lll_cond_trylock(lock) __lll_cond_trylock (&(lock))
2c0b891a 188
043ad426 189
e51deae7
UD
190extern void __lll_lock_wait_private (int *futex) attribute_hidden;
191extern void __lll_lock_wait (int *futex, int private) attribute_hidden;
192extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden;
f3c13160 193
e51deae7 194#define lll_lock(lock, private) \
bd0fa4ce
UD
195 (void) ({ \
196 int *__futex = &(lock); \
39358e8b
UD
197 if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 1, 0),\
198 0) != 0) \
e51deae7
UD
199 { \
200 if (__builtin_constant_p (private) && (private) == LLL_PRIVATE) \
201 __lll_lock_wait_private (__futex); \
202 else \
203 __lll_lock_wait (__futex, private); \
204 } \
f3c13160
RM
205 })
206
e51deae7 207#define lll_robust_lock(lock, id, private) \
f1740bc4
UD
208 ({ \
209 int *__futex = &(lock); \
210 int __val = 0; \
211 if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id, \
212 0), 0)) \
e51deae7 213 __val = __lll_robust_lock_wait (__futex, private); \
f1740bc4
UD
214 __val; \
215 })
216
e51deae7 217#define lll_cond_lock(lock, private) \
b8ba4a27
UD
218 (void) ({ \
219 int *__futex = &(lock); \
39358e8b
UD
220 if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 2, 0),\
221 0) != 0) \
e51deae7 222 __lll_lock_wait (__futex, private); \
b8ba4a27
UD
223 })
224
e51deae7 225#define lll_robust_cond_lock(lock, id, private) \
f1740bc4
UD
226 ({ \
227 int *__futex = &(lock); \
228 int __val = 0; \
229 int __id = id | FUTEX_WAITERS; \
230 if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, __id,\
231 0), 0)) \
e51deae7 232 __val = __lll_robust_lock_wait (__futex, private); \
f1740bc4
UD
233 __val; \
234 })
235
236
f3c13160 237extern int __lll_timedlock_wait
e51deae7 238 (int *futex, const struct timespec *, int private) attribute_hidden;
f1740bc4 239extern int __lll_robust_timedlock_wait
e51deae7 240 (int *futex, const struct timespec *, int private) attribute_hidden;
f3c13160 241
e51deae7 242#define lll_timedlock(lock, abstime, private) \
39358e8b 243 ({ \
bc1989aa 244 int *__futex = &(lock); \
39358e8b
UD
245 int __val = 0; \
246 if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, 1, 0),\
247 0) != 0) \
e51deae7 248 __val = __lll_timedlock_wait (__futex, abstime, private); \
39358e8b 249 __val; \
f3c13160
RM
250 })
251
e51deae7 252#define lll_robust_timedlock(lock, abstime, id, private) \
f1740bc4
UD
253 ({ \
254 int *__futex = &(lock); \
255 int __val = 0; \
256 if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id, \
257 0), 0)) \
e51deae7 258 __val = __lll_robust_timedlock_wait (__futex, abstime, private); \
f1740bc4
UD
259 __val; \
260 })
261
e51deae7 262#define lll_unlock(lock, private) \
94659495 263 ((void) ({ \
bd0fa4ce 264 int *__futex = &(lock); \
7158eae4 265 int __val = atomic_exchange_rel (__futex, 0); \
94659495 266 if (__builtin_expect (__val > 1, 0)) \
e51deae7 267 lll_futex_wake (__futex, 1, private); \
94659495 268 }))
f3c13160 269
e51deae7 270#define lll_robust_unlock(lock, private) \
f1740bc4
UD
271 ((void) ({ \
272 int *__futex = &(lock); \
273 int __val = atomic_exchange_rel (__futex, 0); \
274 if (__builtin_expect (__val & FUTEX_WAITERS, 0)) \
e51deae7 275 lll_futex_wake (__futex, 1, private); \
b8ba4a27
UD
276 }))
277
e51deae7 278#define lll_islocked(futex) \
f3c13160
RM
279 (futex != 0)
280
281
f3c13160
RM
282/* Initializers for lock. */
283#define LLL_LOCK_INITIALIZER (0)
284#define LLL_LOCK_INITIALIZER_LOCKED (1)
285
f3c13160
RM
286/* The states of a lock are:
287 0 - untaken
288 1 - taken by one user
289 >1 - taken by more users */
290
adcdc775 291/* The kernel notifies a process which uses CLONE_CHILD_CLEARTID via futex
f3c13160
RM
292 wakeup when the clone terminates. The memory location contains the
293 thread ID while the clone is running and is reset to zero
294 afterwards. */
bd0fa4ce
UD
295#define lll_wait_tid(tid) \
296 do { \
297 __typeof (tid) __tid; \
298 while ((__tid = (tid)) != 0) \
eb7721f2 299 lll_futex_wait (&(tid), __tid, LLL_SHARED); \
f3c13160
RM
300 } while (0)
301
302extern int __lll_timedwait_tid (int *, const struct timespec *)
303 attribute_hidden;
304
bd0fa4ce
UD
305#define lll_timedwait_tid(tid, abstime) \
306 ({ \
307 int __res = 0; \
308 if ((tid) != 0) \
309 __res = __lll_timedwait_tid (&(tid), (abstime)); \
310 __res; \
f3c13160
RM
311 })
312
f3c13160 313#endif /* lowlevellock.h */