]> 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
688903eb 1/* Copyright (C) 2002-2018 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
683040c3 135
e51deae7 136/* Special version of lll_lock which causes the unlock function to
69431c9a 137 always wakeup waiters. */
e51deae7
UD
138#define lll_cond_lock(futex, private) \
139 (void) \
140 ({ int ignore1, ignore2, ignore3; \
141 __asm __volatile (LOCK_INSTR "cmpxchgl %1, %2\n\t" \
df5b85da 142 "jz 18f\n\t" \
e51deae7
UD
143 "1:\tleal %2, %%edx\n" \
144 "0:\tmovl %7, %%ecx\n" \
145 "2:\tcall __lll_lock_wait\n" \
e51deae7
UD
146 "18:" \
147 : "=a" (ignore1), "=c" (ignore2), "=m" (futex), \
148 "=&d" (ignore3) \
2458c748 149 : "0" (0), "1" (2), "m" (futex), "g" ((int) (private))\
e51deae7
UD
150 : "memory"); \
151 })
152
153
e51deae7
UD
154#define lll_timedlock(futex, timeout, private) \
155 ({ int result, ignore1, ignore2, ignore3; \
71451de2 156 __asm __volatile (LOCK_INSTR "cmpxchgl %1, %3\n\t" \
df5b85da 157 "jz 18f\n\t" \
cd248c3f 158 "1:\tleal %3, %%ecx\n" \
e51deae7
UD
159 "0:\tmovl %8, %%edx\n" \
160 "2:\tcall __lll_timedlock_wait\n" \
cd248c3f 161 "18:" \
71451de2 162 : "=a" (result), "=c" (ignore1), "=&d" (ignore2), \
e51deae7
UD
163 "=m" (futex), "=S" (ignore3) \
164 : "0" (0), "1" (1), "m" (futex), "m" (timeout), \
2458c748 165 "4" ((int) (private)) \
7a5cdb30 166 : "memory"); \
76a50749
UD
167 result; })
168
1cdbe579
AK
169extern int __lll_timedlock_elision (int *futex, short *adapt_count,
170 const struct timespec *timeout,
171 int private) attribute_hidden;
172
173#define lll_timedlock_elision(futex, adapt_count, timeout, private) \
174 __lll_timedlock_elision(&(futex), &(adapt_count), timeout, private)
76a50749 175
4f41c682 176#if !IS_IN (libc) || defined UP
e51deae7 177# define __lll_unlock_asm LOCK_INSTR "subl $1, %0\n\t"
14e7aece 178#else
e51deae7
UD
179# define __lll_unlock_asm "cmpl $0, %%gs:%P3\n\t" \
180 "je 0f\n\t" \
181 "lock\n" \
182 "0:\tsubl $1,%0\n\t"
14e7aece 183#endif
76a50749 184
e51deae7
UD
185#define lll_unlock(futex, private) \
186 (void) \
187 ({ int ignore; \
188 if (__builtin_constant_p (private) && (private) == LLL_PRIVATE) \
189 __asm __volatile (__lll_unlock_asm \
df5b85da 190 "je 18f\n\t" \
e51deae7
UD
191 "1:\tleal %0, %%eax\n" \
192 "2:\tcall __lll_unlock_wake_private\n" \
e51deae7
UD
193 "18:" \
194 : "=m" (futex), "=&a" (ignore) \
195 : "m" (futex), "i" (MULTIPLE_THREADS_OFFSET) \
196 : "memory"); \
197 else \
198 { \
199 int ignore2; \
200 __asm __volatile (__lll_unlock_asm \
df5b85da 201 "je 18f\n\t" \
e51deae7
UD
202 "1:\tleal %0, %%eax\n" \
203 "0:\tmovl %5, %%ecx\n" \
204 "2:\tcall __lll_unlock_wake\n" \
e51deae7
UD
205 "18:" \
206 : "=m" (futex), "=&a" (ignore), "=&c" (ignore2) \
207 : "i" (MULTIPLE_THREADS_OFFSET), "m" (futex), \
2458c748 208 "g" ((int) (private)) \
e51deae7
UD
209 : "memory"); \
210 } \
211 })
212
e51deae7 213
76a50749 214#define lll_islocked(futex) \
71451de2 215 (futex != LLL_LOCK_INITIALIZER)
76a50749 216
adcdc775 217/* The kernel notifies a process which uses CLONE_CHILD_CLEARTID via futex
a4a43a90
TR
218 wake-up when the clone terminates. The memory location contains the
219 thread ID while the clone is running and is reset to zero by the kernel
220 afterwards. The kernel up to version 3.16.3 does not use the private futex
221 operations for futex wake-up when the clone terminates. */
76a50749 222#define lll_wait_tid(tid) \
a4a43a90
TR
223 do { \
224 __typeof (tid) __tid; \
225 while ((__tid = (tid)) != 0) \
226 lll_futex_wait (&(tid), __tid, LLL_SHARED);\
76a50749
UD
227 } while (0)
228
229extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime)
230 __attribute__ ((regparm (2))) attribute_hidden;
a4a43a90
TR
231
232/* As lll_wait_tid, but with a timeout. If the timeout occurs then return
233 ETIMEDOUT. If ABSTIME is invalid, return EINVAL.
234 XXX Note that this differs from the generic version in that we do the
235 error checking here and not in __lll_timedwait_tid. */
76a50749
UD
236#define lll_timedwait_tid(tid, abstime) \
237 ({ \
238 int __result = 0; \
a4a43a90 239 if ((tid) != 0) \
4735850f 240 __result = __lll_timedwait_tid (&(tid), (abstime)); \
76a50749
UD
241 __result; })
242
a4a43a90 243
1cdbe579
AK
244extern int __lll_lock_elision (int *futex, short *adapt_count, int private)
245 attribute_hidden;
246
247extern int __lll_unlock_elision(int *lock, int private)
248 attribute_hidden;
249
250extern int __lll_trylock_elision(int *lock, short *adapt_count)
251 attribute_hidden;
252
253#define lll_lock_elision(futex, adapt_count, private) \
254 __lll_lock_elision (&(futex), &(adapt_count), private)
5ef19339 255#define lll_unlock_elision(futex, adapt_count, private) \
1cdbe579
AK
256 __lll_unlock_elision (&(futex), private)
257#define lll_trylock_elision(futex, adapt_count) \
258 __lll_trylock_elision(&(futex), &(adapt_count))
259
e51deae7 260#endif /* !__ASSEMBLER__ */
76a50749
UD
261
262#endif /* lowlevellock.h */