]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/unix/sysv/linux/i386/lowlevellock.h
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / sysdeps / unix / sysv / linux / i386 / lowlevellock.h
CommitLineData
f7a9f785 1/* Copyright (C) 2002-2016 Free Software Foundation, Inc.
76a50749
UD
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
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/>. */
76a50749
UD
18
19#ifndef _LOWLEVELLOCK_H
20#define _LOWLEVELLOCK_H 1
21
17557282
RH
22#include <stap-probe.h>
23
e51deae7
UD
24#ifndef __ASSEMBLER__
25# include <time.h>
26# include <sys/param.h>
27# include <bits/pthreadtypes.h>
28# include <kernel-features.h>
29# include <tcb-offsets.h>
30
31# ifndef LOCK_INSTR
32# ifdef UP
33# define LOCK_INSTR /* nothing */
34# else
35# define LOCK_INSTR "lock;"
36# endif
37# endif
38#else
39# ifndef LOCK
40# ifdef UP
41# define LOCK
42# else
43# define LOCK lock
44# endif
76a50749
UD
45# endif
46#endif
47
a4a43a90
TR
48#include <lowlevellock-futex.h>
49
50/* XXX Remove when no assembler code uses futexes anymore. */
a9fe4c5a 51#define SYS_futex __NR_futex
1168be45 52
e51deae7 53#ifndef __ASSEMBLER__
1168be45 54
76a50749 55/* Initializer for compatibility lock. */
e51deae7
UD
56#define LLL_LOCK_INITIALIZER (0)
57#define LLL_LOCK_INITIALIZER_LOCKED (1)
58#define LLL_LOCK_INITIALIZER_WAITERS (2)
76a50749
UD
59
60
e51deae7 61/* NB: in the lll_trylock macro we simply return the value in %eax
e408880b
UD
62 after the cmpxchg instruction. In case the operation succeded this
63 value is zero. In case the operation failed, the cmpxchg instruction
64 has loaded the current value of the memory work which is guaranteed
65 to be nonzero. */
4f41c682 66#if !IS_IN (libc) || defined UP
e51deae7
UD
67# define __lll_trylock_asm LOCK_INSTR "cmpxchgl %2, %1"
68#else
69# define __lll_trylock_asm "cmpl $0, %%gs:%P5\n\t" \
70 "je 0f\n\t" \
71 "lock\n" \
72 "0:\tcmpxchgl %2, %1"
73#endif
74
75#define lll_trylock(futex) \
e408880b 76 ({ int ret; \
e51deae7 77 __asm __volatile (__lll_trylock_asm \
76a50749 78 : "=a" (ret), "=m" (futex) \
e51deae7
UD
79 : "r" (LLL_LOCK_INITIALIZER_LOCKED), "m" (futex), \
80 "0" (LLL_LOCK_INITIALIZER), \
81 "i" (MULTIPLE_THREADS_OFFSET) \
7a5cdb30 82 : "memory"); \
76a50749
UD
83 ret; })
84
683040c3 85
e51deae7 86#define lll_cond_trylock(futex) \
2c0b891a
UD
87 ({ int ret; \
88 __asm __volatile (LOCK_INSTR "cmpxchgl %2, %1" \
89 : "=a" (ret), "=m" (futex) \
e51deae7
UD
90 : "r" (LLL_LOCK_INITIALIZER_WAITERS), \
91 "m" (futex), "0" (LLL_LOCK_INITIALIZER) \
2c0b891a
UD
92 : "memory"); \
93 ret; })
94
4f41c682 95#if !IS_IN (libc) || defined UP
e51deae7
UD
96# define __lll_lock_asm_start LOCK_INSTR "cmpxchgl %1, %2\n\t"
97#else
98# define __lll_lock_asm_start "cmpl $0, %%gs:%P6\n\t" \
99 "je 0f\n\t" \
100 "lock\n" \
101 "0:\tcmpxchgl %1, %2\n\t"
102#endif
2c0b891a 103
e51deae7
UD
104#define lll_lock(futex, private) \
105 (void) \
106 ({ int ignore1, ignore2; \
107 if (__builtin_constant_p (private) && (private) == LLL_PRIVATE) \
108 __asm __volatile (__lll_lock_asm_start \
df5b85da 109 "jz 18f\n\t" \
e51deae7
UD
110 "1:\tleal %2, %%ecx\n" \
111 "2:\tcall __lll_lock_wait_private\n" \
e51deae7
UD
112 "18:" \
113 : "=a" (ignore1), "=c" (ignore2), "=m" (futex) \
114 : "0" (0), "1" (1), "m" (futex), \
115 "i" (MULTIPLE_THREADS_OFFSET) \
116 : "memory"); \
117 else \
118 { \
119 int ignore3; \
120 __asm __volatile (__lll_lock_asm_start \
df5b85da 121 "jz 18f\n\t" \
e51deae7
UD
122 "1:\tleal %2, %%edx\n" \
123 "0:\tmovl %8, %%ecx\n" \
124 "2:\tcall __lll_lock_wait\n" \
e51deae7
UD
125 "18:" \
126 : "=a" (ignore1), "=c" (ignore2), \
127 "=m" (futex), "=&d" (ignore3) \
128 : "1" (1), "m" (futex), \
129 "i" (MULTIPLE_THREADS_OFFSET), "0" (0), \
2458c748 130 "g" ((int) (private)) \
e51deae7
UD
131 : "memory"); \
132 } \
133 })
134
135#define lll_robust_lock(futex, id, private) \
136 ({ int result, ignore1, ignore2; \
683040c3 137 __asm __volatile (LOCK_INSTR "cmpxchgl %1, %2\n\t" \
df5b85da 138 "jz 18f\n\t" \
e51deae7
UD
139 "1:\tleal %2, %%edx\n" \
140 "0:\tmovl %7, %%ecx\n" \
141 "2:\tcall __lll_robust_lock_wait\n" \
cd248c3f 142 "18:" \
e51deae7
UD
143 : "=a" (result), "=c" (ignore1), "=m" (futex), \
144 "=&d" (ignore2) \
2458c748 145 : "0" (0), "1" (id), "m" (futex), "g" ((int) (private))\
683040c3
UD
146 : "memory"); \
147 result; })
148
149
e51deae7 150/* Special version of lll_lock which causes the unlock function to
69431c9a 151 always wakeup waiters. */
e51deae7
UD
152#define lll_cond_lock(futex, private) \
153 (void) \
154 ({ int ignore1, ignore2, ignore3; \
155 __asm __volatile (LOCK_INSTR "cmpxchgl %1, %2\n\t" \
df5b85da 156 "jz 18f\n\t" \
e51deae7
UD
157 "1:\tleal %2, %%edx\n" \
158 "0:\tmovl %7, %%ecx\n" \
159 "2:\tcall __lll_lock_wait\n" \
e51deae7
UD
160 "18:" \
161 : "=a" (ignore1), "=c" (ignore2), "=m" (futex), \
162 "=&d" (ignore3) \
2458c748 163 : "0" (0), "1" (2), "m" (futex), "g" ((int) (private))\
e51deae7
UD
164 : "memory"); \
165 })
166
167
168#define lll_robust_cond_lock(futex, id, private) \
169 ({ int result, ignore1, ignore2; \
683040c3 170 __asm __volatile (LOCK_INSTR "cmpxchgl %1, %2\n\t" \
df5b85da 171 "jz 18f\n\t" \
e51deae7
UD
172 "1:\tleal %2, %%edx\n" \
173 "0:\tmovl %7, %%ecx\n" \
174 "2:\tcall __lll_robust_lock_wait\n" \
cd248c3f 175 "18:" \
e51deae7
UD
176 : "=a" (result), "=c" (ignore1), "=m" (futex), \
177 "=&d" (ignore2) \
178 : "0" (0), "1" (id | FUTEX_WAITERS), "m" (futex), \
2458c748 179 "g" ((int) (private)) \
683040c3
UD
180 : "memory"); \
181 result; })
182
183
e51deae7
UD
184#define lll_timedlock(futex, timeout, private) \
185 ({ int result, ignore1, ignore2, ignore3; \
71451de2 186 __asm __volatile (LOCK_INSTR "cmpxchgl %1, %3\n\t" \
df5b85da 187 "jz 18f\n\t" \
cd248c3f 188 "1:\tleal %3, %%ecx\n" \
e51deae7
UD
189 "0:\tmovl %8, %%edx\n" \
190 "2:\tcall __lll_timedlock_wait\n" \
cd248c3f 191 "18:" \
71451de2 192 : "=a" (result), "=c" (ignore1), "=&d" (ignore2), \
e51deae7
UD
193 "=m" (futex), "=S" (ignore3) \
194 : "0" (0), "1" (1), "m" (futex), "m" (timeout), \
2458c748 195 "4" ((int) (private)) \
7a5cdb30 196 : "memory"); \
76a50749
UD
197 result; })
198
1cdbe579
AK
199extern int __lll_timedlock_elision (int *futex, short *adapt_count,
200 const struct timespec *timeout,
201 int private) attribute_hidden;
202
203#define lll_timedlock_elision(futex, adapt_count, timeout, private) \
204 __lll_timedlock_elision(&(futex), &(adapt_count), timeout, private)
76a50749 205
e51deae7
UD
206#define lll_robust_timedlock(futex, timeout, id, private) \
207 ({ int result, ignore1, ignore2, ignore3; \
683040c3 208 __asm __volatile (LOCK_INSTR "cmpxchgl %1, %3\n\t" \
df5b85da 209 "jz 18f\n\t" \
cd248c3f 210 "1:\tleal %3, %%ecx\n" \
e51deae7
UD
211 "0:\tmovl %8, %%edx\n" \
212 "2:\tcall __lll_robust_timedlock_wait\n" \
cd248c3f 213 "18:" \
683040c3 214 : "=a" (result), "=c" (ignore1), "=&d" (ignore2), \
e51deae7
UD
215 "=m" (futex), "=S" (ignore3) \
216 : "0" (0), "1" (id), "m" (futex), "m" (timeout), \
2458c748 217 "4" ((int) (private)) \
683040c3
UD
218 : "memory"); \
219 result; })
220
4f41c682 221#if !IS_IN (libc) || defined UP
e51deae7 222# define __lll_unlock_asm LOCK_INSTR "subl $1, %0\n\t"
14e7aece 223#else
e51deae7
UD
224# define __lll_unlock_asm "cmpl $0, %%gs:%P3\n\t" \
225 "je 0f\n\t" \
226 "lock\n" \
227 "0:\tsubl $1,%0\n\t"
14e7aece 228#endif
76a50749 229
e51deae7
UD
230#define lll_unlock(futex, private) \
231 (void) \
232 ({ int ignore; \
233 if (__builtin_constant_p (private) && (private) == LLL_PRIVATE) \
234 __asm __volatile (__lll_unlock_asm \
df5b85da 235 "je 18f\n\t" \
e51deae7
UD
236 "1:\tleal %0, %%eax\n" \
237 "2:\tcall __lll_unlock_wake_private\n" \
e51deae7
UD
238 "18:" \
239 : "=m" (futex), "=&a" (ignore) \
240 : "m" (futex), "i" (MULTIPLE_THREADS_OFFSET) \
241 : "memory"); \
242 else \
243 { \
244 int ignore2; \
245 __asm __volatile (__lll_unlock_asm \
df5b85da 246 "je 18f\n\t" \
e51deae7
UD
247 "1:\tleal %0, %%eax\n" \
248 "0:\tmovl %5, %%ecx\n" \
249 "2:\tcall __lll_unlock_wake\n" \
e51deae7
UD
250 "18:" \
251 : "=m" (futex), "=&a" (ignore), "=&c" (ignore2) \
252 : "i" (MULTIPLE_THREADS_OFFSET), "m" (futex), \
2458c748 253 "g" ((int) (private)) \
e51deae7
UD
254 : "memory"); \
255 } \
256 })
257
258#define lll_robust_unlock(futex, private) \
259 (void) \
260 ({ int ignore, ignore2; \
261 __asm __volatile (LOCK_INSTR "andl %3, %0\n\t" \
df5b85da 262 "je 18f\n\t" \
e51deae7
UD
263 "1:\tleal %0, %%eax\n" \
264 "0:\tmovl %5, %%ecx\n" \
265 "2:\tcall __lll_unlock_wake\n" \
e51deae7
UD
266 "18:" \
267 : "=m" (futex), "=&a" (ignore), "=&c" (ignore2) \
2458c748
AJ
268 : "i" (FUTEX_WAITERS), "m" (futex), \
269 "g" ((int) (private)) \
e51deae7
UD
270 : "memory"); \
271 })
272
273
76a50749 274#define lll_islocked(futex) \
71451de2 275 (futex != LLL_LOCK_INITIALIZER)
76a50749 276
adcdc775 277/* The kernel notifies a process which uses CLONE_CHILD_CLEARTID via futex
a4a43a90
TR
278 wake-up when the clone terminates. The memory location contains the
279 thread ID while the clone is running and is reset to zero by the kernel
280 afterwards. The kernel up to version 3.16.3 does not use the private futex
281 operations for futex wake-up when the clone terminates. */
76a50749 282#define lll_wait_tid(tid) \
a4a43a90
TR
283 do { \
284 __typeof (tid) __tid; \
285 while ((__tid = (tid)) != 0) \
286 lll_futex_wait (&(tid), __tid, LLL_SHARED);\
76a50749
UD
287 } while (0)
288
289extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime)
290 __attribute__ ((regparm (2))) attribute_hidden;
a4a43a90
TR
291
292/* As lll_wait_tid, but with a timeout. If the timeout occurs then return
293 ETIMEDOUT. If ABSTIME is invalid, return EINVAL.
294 XXX Note that this differs from the generic version in that we do the
295 error checking here and not in __lll_timedwait_tid. */
76a50749
UD
296#define lll_timedwait_tid(tid, abstime) \
297 ({ \
298 int __result = 0; \
a4a43a90 299 if ((tid) != 0) \
76a50749 300 { \
a4a43a90 301 if ((abstime)->tv_nsec < 0 || (abstime)->tv_nsec >= 1000000000) \
76a50749
UD
302 __result = EINVAL; \
303 else \
a4a43a90 304 __result = __lll_timedwait_tid (&(tid), (abstime)); \
76a50749
UD
305 } \
306 __result; })
307
a4a43a90 308
1cdbe579
AK
309extern int __lll_lock_elision (int *futex, short *adapt_count, int private)
310 attribute_hidden;
311
312extern int __lll_unlock_elision(int *lock, int private)
313 attribute_hidden;
314
315extern int __lll_trylock_elision(int *lock, short *adapt_count)
316 attribute_hidden;
317
318#define lll_lock_elision(futex, adapt_count, private) \
319 __lll_lock_elision (&(futex), &(adapt_count), private)
5ef19339 320#define lll_unlock_elision(futex, adapt_count, private) \
1cdbe579
AK
321 __lll_unlock_elision (&(futex), private)
322#define lll_trylock_elision(futex, adapt_count) \
323 __lll_trylock_elision(&(futex), &(adapt_count))
324
e51deae7 325#endif /* !__ASSEMBLER__ */
76a50749
UD
326
327#endif /* lowlevellock.h */