]> git.ipfire.org Git - thirdparty/glibc.git/blame - nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h
Update.
[thirdparty/glibc.git] / nptl / sysdeps / unix / sysv / linux / i386 / lowlevellock.h
CommitLineData
16b06b70 1/* Copyright (C) 2002, 2003, 2004 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
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. */
19
20#ifndef _LOWLEVELLOCK_H
21#define _LOWLEVELLOCK_H 1
22
23#include <time.h>
9ae0909b 24#include <sys/param.h>
76a50749
UD
25#include <bits/pthreadtypes.h>
26
27#ifndef LOCK_INSTR
28# ifdef UP
29# define LOCK_INSTR /* nothing */
30# else
31# define LOCK_INSTR "lock;"
32# endif
33#endif
34
35#define SYS_futex 240
36#define FUTEX_WAIT 0
37#define FUTEX_WAKE 1
38
39
40/* Initializer for compatibility lock. */
71451de2
UD
41#define LLL_MUTEX_LOCK_INITIALIZER (0)
42#define LLL_MUTEX_LOCK_INITIALIZER_LOCKED (1)
76a50749
UD
43
44
949ec764
UD
45#ifdef PIC
46# define LLL_EBX_LOAD "xchgl %2, %%ebx\n"
47# define LLL_EBX_REG "D"
48#else
49# define LLL_EBX_LOAD
50# define LLL_EBX_REG "b"
51#endif
52
53#ifdef I386_USE_SYSENTER
54# ifdef SHARED
20945457 55# define LLL_ENTER_KERNEL "call *%%gs:%P6\n\t"
949ec764 56# else
20945457 57# define LLL_ENTER_KERNEL "call *_dl_sysinfo\n\t"
949ec764
UD
58# endif
59#else
60# define LLL_ENTER_KERNEL "int $0x80\n\t"
61#endif
62
92d83c72
UD
63
64#define lll_futex_wait(futex, val) \
65 do { \
66 int __ignore; \
67 register __typeof (val) _val asm ("edx") = (val); \
949ec764 68 __asm __volatile (LLL_EBX_LOAD \
92d83c72 69 LLL_ENTER_KERNEL \
949ec764 70 LLL_EBX_LOAD \
92d83c72 71 : "=a" (__ignore) \
20945457 72 : "0" (SYS_futex), LLL_EBX_REG (futex), "S" (0), \
92d83c72
UD
73 "c" (FUTEX_WAIT), "d" (_val), \
74 "i" (offsetof (tcbhead_t, sysinfo))); \
75 } while (0)
76
77
78#define lll_futex_wake(futex, nr) \
79 do { \
80 int __ignore; \
81 register __typeof (nr) _nr asm ("edx") = (nr); \
949ec764 82 __asm __volatile (LLL_EBX_LOAD \
92d83c72 83 LLL_ENTER_KERNEL \
949ec764 84 LLL_EBX_LOAD \
92d83c72 85 : "=a" (__ignore) \
20945457 86 : "0" (SYS_futex), LLL_EBX_REG (futex), \
949ec764
UD
87 "c" (FUTEX_WAKE), "d" (_nr), \
88 "i" (0) /* phony, to align next arg's number */, \
92d83c72
UD
89 "i" (offsetof (tcbhead_t, sysinfo))); \
90 } while (0)
91
92
76a50749
UD
93/* Does not preserve %eax and %ecx. */
94extern int __lll_mutex_lock_wait (int val, int *__futex)
95 __attribute ((regparm (2))) attribute_hidden;
20945457 96/* Does not preserve %eax, %ecx, and %edx. */
76a50749 97extern int __lll_mutex_timedlock_wait (int val, int *__futex,
6ff19c81 98 const struct timespec *abstime)
76a50749
UD
99 __attribute ((regparm (3))) attribute_hidden;
100/* Preserves all registers but %eax. */
71451de2 101extern int __lll_mutex_unlock_wake (int *__futex)
76a50749
UD
102 __attribute ((regparm (1))) attribute_hidden;
103
104
105#define lll_mutex_trylock(futex) \
106 ({ unsigned char ret; \
16b06b70 107 __asm __volatile (LOCK_INSTR "cmpxchgl %2, %1" \
76a50749 108 : "=a" (ret), "=m" (futex) \
71451de2
UD
109 : "r" (LLL_MUTEX_LOCK_INITIALIZER_LOCKED), "m" (futex),\
110 "0" (LLL_MUTEX_LOCK_INITIALIZER) \
7a5cdb30 111 : "memory"); \
76a50749
UD
112 ret; })
113
114
115#define lll_mutex_lock(futex) \
116 (void) ({ int ignore1, ignore2; \
71451de2 117 __asm __volatile (LOCK_INSTR "cmpxchgl %1, %2\n\t" \
3a226d33 118 "jnz _L_mutex_lock_%=\n\t" \
8348dcc8
UD
119 ".subsection 1\n\t" \
120 ".type _L_mutex_lock_%=,@function\n" \
121 "_L_mutex_lock_%=:\n\t" \
122 "leal %2, %%ecx\n\t" \
7a5cdb30 123 "call __lll_mutex_lock_wait\n\t" \
8348dcc8
UD
124 "jmp 1f\n\t" \
125 ".size _L_mutex_lock_%=,.-_L_mutex_lock_%=\n" \
7a5cdb30 126 ".previous\n" \
8348dcc8 127 "1:" \
71451de2
UD
128 : "=a" (ignore1), "=c" (ignore2), "=m" (futex) \
129 : "0" (0), "1" (1), "m" (futex) \
7a5cdb30 130 : "memory"); })
76a50749
UD
131
132
69431c9a
UD
133/* Special version of lll_mutex_lock which causes the unlock function to
134 always wakeup waiters. */
135#define lll_mutex_cond_lock(futex) \
136 (void) ({ int ignore1, ignore2; \
71451de2 137 __asm __volatile (LOCK_INSTR "cmpxchgl %1, %2\n\t" \
3a226d33 138 "jnz _L_mutex_cond_lock_%=\n\t" \
8348dcc8
UD
139 ".subsection 1\n\t" \
140 ".type _L_mutex_cond_lock_%=,@function\n" \
141 "_L_mutex_cond_lock_%=:\n\t" \
142 "leal %2, %%ecx\n\t" \
69431c9a 143 "call __lll_mutex_lock_wait\n\t" \
8348dcc8
UD
144 "jmp 1f\n\t" \
145 ".size _L_mutex_cond_lock_%=,.-_L_mutex_cond_lock_%=\n" \
69431c9a 146 ".previous\n" \
8348dcc8 147 "1:" \
71451de2
UD
148 : "=a" (ignore1), "=c" (ignore2), "=m" (futex) \
149 : "0" (0), "1" (2), "m" (futex) \
69431c9a
UD
150 : "memory"); })
151
152
76a50749
UD
153#define lll_mutex_timedlock(futex, timeout) \
154 ({ int result, ignore1, ignore2; \
71451de2 155 __asm __volatile (LOCK_INSTR "cmpxchgl %1, %3\n\t" \
3a226d33 156 "jnz _L_mutex_timedlock_%=\n\t" \
8348dcc8
UD
157 ".subsection 1\n\t" \
158 ".type _L_mutex_timedlock_%=,@function\n" \
159 "_L_mutex_timedlock_%=:\n\t" \
160 "leal %3, %%ecx\n\t" \
71451de2 161 "movl %7, %%edx\n\t" \
7a5cdb30 162 "call __lll_mutex_timedlock_wait\n\t" \
8348dcc8
UD
163 "jmp 1f\n\t" \
164 ".size _L_mutex_timedlock_%=,.-_L_mutex_timedlock_%=\n"\
7a5cdb30 165 ".previous\n" \
8348dcc8 166 "1:" \
71451de2 167 : "=a" (result), "=c" (ignore1), "=&d" (ignore2), \
7a5cdb30 168 "=m" (futex) \
71451de2 169 : "0" (0), "1" (1), "m" (futex), "m" (timeout) \
7a5cdb30 170 : "memory"); \
76a50749
UD
171 result; })
172
173
174#define lll_mutex_unlock(futex) \
175 (void) ({ int ignore; \
ccf1d573 176 __asm __volatile (LOCK_INSTR "subl $1,%0\n\t" \
8348dcc8
UD
177 "jne _L_mutex_unlock_%=\n\t" \
178 ".subsection 1\n\t" \
179 ".type _L_mutex_unlock_%=,@function\n" \
180 "_L_mutex_unlock_%=:\n\t" \
181 "leal %0, %%eax\n\t" \
7a5cdb30 182 "call __lll_mutex_unlock_wake\n\t" \
8348dcc8
UD
183 "jmp 1f\n\t" \
184 ".size _L_mutex_unlock_%=,.-_L_mutex_unlock_%=\n" \
7a5cdb30 185 ".previous\n" \
8348dcc8 186 "1:" \
7a5cdb30 187 : "=m" (futex), "=&a" (ignore) \
56a4aa98 188 : "m" (futex) \
7a5cdb30 189 : "memory"); })
76a50749
UD
190
191
192#define lll_mutex_islocked(futex) \
193 (futex != 0)
194
195
196/* We have a separate internal lock implementation which is not tied
197 to binary compatibility. */
198
199/* Type for lock object. */
200typedef int lll_lock_t;
201
202/* Initializers for lock. */
71451de2
UD
203#define LLL_LOCK_INITIALIZER (0)
204#define LLL_LOCK_INITIALIZER_LOCKED (1)
76a50749
UD
205
206
207extern int __lll_lock_wait (int val, int *__futex)
208 __attribute ((regparm (2))) attribute_hidden;
209extern int __lll_unlock_wake (int *__futex)
210 __attribute ((regparm (1))) attribute_hidden;
211extern int lll_unlock_wake_cb (int *__futex) attribute_hidden;
212
213
214/* The states of a lock are:
71451de2
UD
215 0 - untaken
216 1 - taken by one user
217 2 - taken by more users */
76a50749
UD
218
219
14e7aece 220#if defined NOT_IN_libc || defined UP
71451de2
UD
221# define lll_trylock(futex) lll_mutex_trylock (futex)
222# define lll_lock(futex) lll_mutex_lock (futex)
223# define lll_unlock(futex) lll_mutex_unlock (futex)
14e7aece
UD
224#else
225/* Special versions of the macros for use in libc itself. They avoid
226 the lock prefix when the thread library is not used.
227
228 XXX In future we might even want to avoid it on UP machines. */
9ae0909b 229# include <tls.h>
14e7aece
UD
230
231# define lll_trylock(futex) \
232 ({ unsigned char ret; \
9ae0909b 233 __asm __volatile ("cmpl $0, %%gs:%P5\n\t" \
14e7aece
UD
234 "je,pt 0f\n\t" \
235 "lock\n" \
236 "0:\tcmpxchgl %2, %1; setne %0" \
237 : "=a" (ret), "=m" (futex) \
71451de2
UD
238 : "r" (LLL_MUTEX_LOCK_INITIALIZER_LOCKED), "m" (futex),\
239 "0" (LLL_MUTEX_LOCK_INITIALIZER), \
9ae0909b 240 "i" (offsetof (tcbhead_t, multiple_threads)) \
14e7aece
UD
241 : "memory"); \
242 ret; })
243
244
245# define lll_lock(futex) \
246 (void) ({ int ignore1, ignore2; \
71451de2 247 __asm __volatile ("cmpl $0, %%gs:%P6\n\t" \
14e7aece
UD
248 "je,pt 0f\n\t" \
249 "lock\n" \
71451de2 250 "0:\tcmpxchgl %1, %2\n\t" \
3a226d33 251 "jnz _L_mutex_lock_%=\n\t" \
8348dcc8 252 ".subsection 1\n\t" \
71451de2
UD
253 ".type _L_mutex_lock_%=,@function\n" \
254 "_L_mutex_lock_%=:\n\t" \
8348dcc8 255 "leal %2, %%ecx\n\t" \
71451de2
UD
256 "call __lll_mutex_lock_wait\n\t" \
257 "jmp 1f\n\t" \
258 ".size _L_mutex_lock_%=,.-_L_mutex_lock_%=\n" \
14e7aece 259 ".previous\n" \
71451de2
UD
260 "1:" \
261 : "=a" (ignore1), "=c" (ignore2), "=m" (futex) \
262 : "0" (0), "1" (1), "m" (futex), \
9ae0909b 263 "i" (offsetof (tcbhead_t, multiple_threads)) \
14e7aece
UD
264 : "memory"); })
265
266
267# define lll_unlock(futex) \
268 (void) ({ int ignore; \
9ae0909b 269 __asm __volatile ("cmpl $0, %%gs:%P3\n\t" \
14e7aece
UD
270 "je,pt 0f\n\t" \
271 "lock\n" \
71451de2
UD
272 "0:\tsubl $1,%0\n\t" \
273 "jne _L_mutex_unlock_%=\n\t" \
8348dcc8 274 ".subsection 1\n\t" \
71451de2
UD
275 ".type _L_mutex_unlock_%=,@function\n" \
276 "_L_mutex_unlock_%=:\n\t" \
8348dcc8 277 "leal %0, %%eax\n\t" \
71451de2
UD
278 "call __lll_mutex_unlock_wake\n\t" \
279 "jmp 1f\n\t" \
280 ".size _L_mutex_unlock_%=,.-_L_mutex_unlock_%=\n" \
14e7aece 281 ".previous\n" \
71451de2 282 "1:" \
14e7aece 283 : "=m" (futex), "=&a" (ignore) \
56a4aa98 284 : "m" (futex), \
9ae0909b 285 "i" (offsetof (tcbhead_t, multiple_threads)) \
14e7aece
UD
286 : "memory"); })
287#endif
76a50749
UD
288
289
290#define lll_islocked(futex) \
71451de2 291 (futex != LLL_LOCK_INITIALIZER)
76a50749
UD
292
293
294/* The kernel notifies a process with uses CLONE_CLEARTID via futex
295 wakeup when the clone terminates. The memory location contains the
296 thread ID while the clone is running and is reset to zero
297 afterwards.
298
299 The macro parameter must not have any side effect. */
76a50749
UD
300#define lll_wait_tid(tid) \
301 do { \
302 int __ignore; \
303 register __typeof (tid) _tid asm ("edx") = (tid); \
304 if (_tid != 0) \
949ec764 305 __asm __volatile (LLL_EBX_LOAD \
76a50749 306 "1:\tmovl %1, %%eax\n\t" \
949ec764 307 LLL_ENTER_KERNEL \
76a50749
UD
308 "cmpl $0, (%%ebx)\n\t" \
309 "jne,pn 1b\n\t" \
949ec764 310 LLL_EBX_LOAD \
76a50749 311 : "=&a" (__ignore) \
949ec764 312 : "i" (SYS_futex), LLL_EBX_REG (&tid), "S" (0), \
097eca29
UD
313 "c" (FUTEX_WAIT), "d" (_tid), \
314 "i" (offsetof (tcbhead_t, sysinfo))); \
76a50749
UD
315 } while (0)
316
317extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime)
318 __attribute__ ((regparm (2))) attribute_hidden;
319#define lll_timedwait_tid(tid, abstime) \
320 ({ \
321 int __result = 0; \
322 if (tid != 0) \
323 { \
31195be2 324 if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) \
76a50749
UD
325 __result = EINVAL; \
326 else \
327 __result = __lll_timedwait_tid (&tid, abstime); \
328 } \
329 __result; })
330
331
76a50749
UD
332/* Conditional variable handling. */
333
334extern void __lll_cond_wait (pthread_cond_t *cond)
335 __attribute ((regparm (1))) attribute_hidden;
336extern int __lll_cond_timedwait (pthread_cond_t *cond,
337 const struct timespec *abstime)
338 __attribute ((regparm (2))) attribute_hidden;
339extern void __lll_cond_wake (pthread_cond_t *cond)
340 __attribute ((regparm (1))) attribute_hidden;
341extern void __lll_cond_broadcast (pthread_cond_t *cond)
342 __attribute ((regparm (1))) attribute_hidden;
343
344
345#define lll_cond_wait(cond) \
346 __lll_cond_wait (cond)
347#define lll_cond_timedwait(cond, abstime) \
348 __lll_cond_timedwait (cond, abstime)
349#define lll_cond_wake(cond) \
350 __lll_cond_wake (cond)
351#define lll_cond_broadcast(cond) \
352 __lll_cond_broadcast (cond)
353
354
355#endif /* lowlevellock.h */