]> git.ipfire.org Git - thirdparty/glibc.git/blob - nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h
* pthread_getattr_np.c: No need to install a cancellation handler,
[thirdparty/glibc.git] / nptl / sysdeps / unix / sysv / linux / x86_64 / lowlevellock.h
1 /* Copyright (C) 2002, 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
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>
24 #include <sys/param.h>
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 202
36 #define FUTEX_WAIT 0
37 #define FUTEX_WAKE 1
38 #define FUTEX_CMP_REQUEUE 4
39 #define FUTEX_LOCK_PI 6
40 #define FUTEX_UNLOCK_PI 7
41 #define FUTEX_TRYLOCK_PI 8
42 #define FUTEX_PRIVATE_FLAG 128
43
44
45 /* Initializer for compatibility lock. */
46 #define LLL_MUTEX_LOCK_INITIALIZER (0)
47 #define LLL_MUTEX_LOCK_INITIALIZER_LOCKED (1)
48 #define LLL_MUTEX_LOCK_INITIALIZER_WAITERS (2)
49
50 /* Delay in spinlock loop. */
51 #define BUSY_WAIT_NOP asm ("rep; nop")
52
53
54 #define LLL_STUB_UNWIND_INFO_START \
55 ".section .eh_frame,\"a\",@progbits\n" \
56 "7:\t" ".long 9f-8f # Length of Common Information Entry\n" \
57 "8:\t" ".long 0x0 # CIE Identifier Tag\n\t" \
58 ".byte 0x1 # CIE Version\n\t" \
59 ".ascii \"zR\\0\" # CIE Augmentation\n\t" \
60 ".uleb128 0x1 # CIE Code Alignment Factor\n\t" \
61 ".sleb128 -8 # CIE Data Alignment Factor\n\t" \
62 ".byte 0x10 # CIE RA Column\n\t" \
63 ".uleb128 0x1 # Augmentation size\n\t" \
64 ".byte 0x1b # FDE Encoding (pcrel sdata4)\n\t" \
65 ".byte 0x12 # DW_CFA_def_cfa_sf\n\t" \
66 ".uleb128 0x7\n\t" \
67 ".sleb128 16\n\t" \
68 ".align 8\n" \
69 "9:\t" ".long 23f-10f # FDE Length\n" \
70 "10:\t" ".long 10b-7b # FDE CIE offset\n\t" \
71 ".long 1b-. # FDE initial location\n\t" \
72 ".long 6b-1b # FDE address range\n\t" \
73 ".uleb128 0x0 # Augmentation size\n\t" \
74 ".byte 0x16 # DW_CFA_val_expression\n\t" \
75 ".uleb128 0x10\n\t" \
76 ".uleb128 12f-11f\n" \
77 "11:\t" ".byte 0x80 # DW_OP_breg16\n\t" \
78 ".sleb128 4b-1b\n"
79 #define LLL_STUB_UNWIND_INFO_END \
80 ".byte 0x16 # DW_CFA_val_expression\n\t" \
81 ".uleb128 0x10\n\t" \
82 ".uleb128 14f-13f\n" \
83 "13:\t" ".byte 0x80 # DW_OP_breg16\n\t" \
84 ".sleb128 4b-2b\n" \
85 "14:\t" ".byte 0x40 + (3b-2b) # DW_CFA_advance_loc\n\t" \
86 ".byte 0x0e # DW_CFA_def_cfa_offset\n\t" \
87 ".uleb128 0\n\t" \
88 ".byte 0x16 # DW_CFA_val_expression\n\t" \
89 ".uleb128 0x10\n\t" \
90 ".uleb128 16f-15f\n" \
91 "15:\t" ".byte 0x80 # DW_OP_breg16\n\t" \
92 ".sleb128 4b-3b\n" \
93 "16:\t" ".byte 0x40 + (4b-3b-1) # DW_CFA_advance_loc\n\t" \
94 ".byte 0x0e # DW_CFA_def_cfa_offset\n\t" \
95 ".uleb128 128\n\t" \
96 ".byte 0x16 # DW_CFA_val_expression\n\t" \
97 ".uleb128 0x10\n\t" \
98 ".uleb128 20f-17f\n" \
99 "17:\t" ".byte 0x80 # DW_OP_breg16\n\t" \
100 ".sleb128 19f-18f\n\t" \
101 ".byte 0x0d # DW_OP_const4s\n" \
102 "18:\t" ".4byte 4b-.\n\t" \
103 ".byte 0x1c # DW_OP_minus\n\t" \
104 ".byte 0x0d # DW_OP_const4s\n" \
105 "19:\t" ".4byte 24f-.\n\t" \
106 ".byte 0x22 # DW_OP_plus\n" \
107 "20:\t" ".byte 0x40 + (5b-4b+1) # DW_CFA_advance_loc\n\t" \
108 ".byte 0x13 # DW_CFA_def_cfa_offset_sf\n\t" \
109 ".sleb128 16\n\t" \
110 ".byte 0x16 # DW_CFA_val_expression\n\t" \
111 ".uleb128 0x10\n\t" \
112 ".uleb128 22f-21f\n" \
113 "21:\t" ".byte 0x80 # DW_OP_breg16\n\t" \
114 ".sleb128 4b-5b\n" \
115 "22:\t" ".align 8\n" \
116 "23:\t" ".previous\n"
117
118 /* Unwind info for
119 1: leaq ..., %rdi
120 2: subq $128, %rsp
121 3: callq ...
122 4: addq $128, %rsp
123 5: jmp 24f
124 6:
125 snippet. */
126 #define LLL_STUB_UNWIND_INFO_5 \
127 LLL_STUB_UNWIND_INFO_START \
128 "12:\t" ".byte 0x40 + (2b-1b) # DW_CFA_advance_loc\n\t" \
129 LLL_STUB_UNWIND_INFO_END
130
131 /* Unwind info for
132 1: leaq ..., %rdi
133 0: movq ..., %rdx
134 2: subq $128, %rsp
135 3: callq ...
136 4: addq $128, %rsp
137 5: jmp 24f
138 6:
139 snippet. */
140 #define LLL_STUB_UNWIND_INFO_6 \
141 LLL_STUB_UNWIND_INFO_START \
142 "12:\t" ".byte 0x40 + (0b-1b) # DW_CFA_advance_loc\n\t" \
143 ".byte 0x16 # DW_CFA_val_expression\n\t" \
144 ".uleb128 0x10\n\t" \
145 ".uleb128 26f-25f\n" \
146 "25:\t" ".byte 0x80 # DW_OP_breg16\n\t" \
147 ".sleb128 4b-0b\n" \
148 "26:\t" ".byte 0x40 + (2b-0b) # DW_CFA_advance_loc\n\t" \
149 LLL_STUB_UNWIND_INFO_END
150
151
152 #define lll_futex_wait(futex, val) \
153 ({ \
154 int __status; \
155 register __typeof (val) _val __asm ("edx") = (val); \
156 __asm __volatile ("xorq %%r10, %%r10\n\t" \
157 "syscall" \
158 : "=a" (__status) \
159 : "0" (SYS_futex), "D" (futex), "S" (FUTEX_WAIT), \
160 "d" (_val) \
161 : "memory", "cc", "r10", "r11", "cx"); \
162 __status; \
163 })
164
165
166 #define lll_futex_timed_wait(futex, val, timeout) \
167 ({ \
168 register const struct timespec *__to __asm ("r10") = timeout; \
169 int __status; \
170 register __typeof (val) _val __asm ("edx") = (val); \
171 __asm __volatile ("syscall" \
172 : "=a" (__status) \
173 : "0" (SYS_futex), "D" (futex), "S" (FUTEX_WAIT), \
174 "d" (_val), "r" (__to) \
175 : "memory", "cc", "r11", "cx"); \
176 __status; \
177 })
178
179
180 #define lll_futex_wake(futex, nr) \
181 do { \
182 int __ignore; \
183 register __typeof (nr) _nr __asm ("edx") = (nr); \
184 __asm __volatile ("syscall" \
185 : "=a" (__ignore) \
186 : "0" (SYS_futex), "D" (futex), "S" (FUTEX_WAKE), \
187 "d" (_nr) \
188 : "memory", "cc", "r10", "r11", "cx"); \
189 } while (0)
190
191
192 /* Does not preserve %eax and %ecx. */
193 extern int __lll_mutex_lock_wait (int *__futex, int __val) attribute_hidden;
194 /* Does not preserver %eax, %ecx, and %edx. */
195 extern int __lll_mutex_timedlock_wait (int *__futex, int __val,
196 const struct timespec *__abstime)
197 attribute_hidden;
198 /* Preserves all registers but %eax. */
199 extern int __lll_mutex_unlock_wait (int *__futex) attribute_hidden;
200
201
202 /* NB: in the lll_mutex_trylock macro we simply return the value in %eax
203 after the cmpxchg instruction. In case the operation succeded this
204 value is zero. In case the operation failed, the cmpxchg instruction
205 has loaded the current value of the memory work which is guaranteed
206 to be nonzero. */
207 #define lll_mutex_trylock(futex) \
208 ({ int ret; \
209 __asm __volatile (LOCK_INSTR "cmpxchgl %2, %1" \
210 : "=a" (ret), "=m" (futex) \
211 : "r" (LLL_MUTEX_LOCK_INITIALIZER_LOCKED), "m" (futex),\
212 "0" (LLL_MUTEX_LOCK_INITIALIZER) \
213 : "memory"); \
214 ret; })
215
216
217 #define lll_robust_mutex_trylock(futex, id) \
218 ({ int ret; \
219 __asm __volatile (LOCK_INSTR "cmpxchgl %2, %1" \
220 : "=a" (ret), "=m" (futex) \
221 : "r" (id), "m" (futex), \
222 "0" (LLL_MUTEX_LOCK_INITIALIZER) \
223 : "memory"); \
224 ret; })
225
226
227 #define lll_mutex_cond_trylock(futex) \
228 ({ int ret; \
229 __asm __volatile (LOCK_INSTR "cmpxchgl %2, %1" \
230 : "=a" (ret), "=m" (futex) \
231 : "r" (LLL_MUTEX_LOCK_INITIALIZER_WAITERS), \
232 "m" (futex), "0" (LLL_MUTEX_LOCK_INITIALIZER) \
233 : "memory"); \
234 ret; })
235
236
237 #define lll_mutex_lock(futex) \
238 (void) ({ int ignore1, ignore2, ignore3; \
239 __asm __volatile (LOCK_INSTR "cmpxchgl %0, %2\n\t" \
240 "jnz 1f\n\t" \
241 ".subsection 1\n\t" \
242 ".type _L_mutex_lock_%=, @function\n" \
243 "_L_mutex_lock_%=:\n" \
244 "1:\tleaq %2, %%rdi\n" \
245 "2:\tsubq $128, %%rsp\n" \
246 "3:\tcallq __lll_mutex_lock_wait\n" \
247 "4:\taddq $128, %%rsp\n" \
248 "5:\tjmp 24f\n" \
249 "6:\t.size _L_mutex_lock_%=, 6b-1b\n\t" \
250 ".previous\n" \
251 LLL_STUB_UNWIND_INFO_5 \
252 "24:" \
253 : "=S" (ignore1), "=&D" (ignore2), "=m" (futex),\
254 "=a" (ignore3) \
255 : "0" (1), "m" (futex), "3" (0) \
256 : "cx", "r11", "cc", "memory"); })
257
258
259 #define lll_robust_mutex_lock(futex, id) \
260 ({ int result, ignore1, ignore2; \
261 __asm __volatile (LOCK_INSTR "cmpxchgl %0, %2\n\t" \
262 "jnz 1f\n\t" \
263 ".subsection 1\n\t" \
264 ".type _L_robust_mutex_lock_%=, @function\n" \
265 "_L_robust_mutex_lock_%=:\n" \
266 "1:\tleaq %2, %%rdi\n" \
267 "2:\tsubq $128, %%rsp\n" \
268 "3:\tcallq __lll_robust_mutex_lock_wait\n" \
269 "4:\taddq $128, %%rsp\n" \
270 "5:\tjmp 24f\n" \
271 "6:\t.size _L_robust_mutex_lock_%=, 6b-1b\n\t" \
272 ".previous\n" \
273 LLL_STUB_UNWIND_INFO_5 \
274 "24:" \
275 : "=S" (ignore1), "=&D" (ignore2), "=m" (futex), \
276 "=a" (result) \
277 : "0" (id), "m" (futex), "3" (0) \
278 : "cx", "r11", "cc", "memory"); \
279 result; })
280
281
282 #define lll_mutex_cond_lock(futex) \
283 (void) ({ int ignore1, ignore2, ignore3; \
284 __asm __volatile (LOCK_INSTR "cmpxchgl %0, %2\n\t" \
285 "jnz 1f\n\t" \
286 ".subsection 1\n\t" \
287 ".type _L_mutex_cond_lock_%=, @function\n" \
288 "_L_mutex_cond_lock_%=:\n" \
289 "1:\tleaq %2, %%rdi\n" \
290 "2:\tsubq $128, %%rsp\n" \
291 "3:\tcallq __lll_mutex_lock_wait\n" \
292 "4:\taddq $128, %%rsp\n" \
293 "5:\tjmp 24f\n" \
294 "6:\t.size _L_mutex_cond_lock_%=, 6b-1b\n\t" \
295 ".previous\n" \
296 LLL_STUB_UNWIND_INFO_5 \
297 "24:" \
298 : "=S" (ignore1), "=&D" (ignore2), "=m" (futex),\
299 "=a" (ignore3) \
300 : "0" (2), "m" (futex), "3" (0) \
301 : "cx", "r11", "cc", "memory"); })
302
303
304 #define lll_robust_mutex_cond_lock(futex, id) \
305 ({ int result, ignore1, ignore2; \
306 __asm __volatile (LOCK_INSTR "cmpxchgl %0, %2\n\t" \
307 "jnz 1f\n\t" \
308 ".subsection 1\n\t" \
309 ".type _L_robust_mutex_cond_lock_%=, @function\n" \
310 "_L_robust_mutex_cond_lock_%=:\n" \
311 "1:\tleaq %2, %%rdi\n" \
312 "2:\tsubq $128, %%rsp\n" \
313 "3:\tcallq __lll_robust_mutex_lock_wait\n" \
314 "4:\taddq $128, %%rsp\n" \
315 "5:\tjmp 24f\n" \
316 "6:\t.size _L_robust_mutex_cond_lock_%=, 6b-1b\n\t" \
317 ".previous\n" \
318 LLL_STUB_UNWIND_INFO_5 \
319 "24:" \
320 : "=S" (ignore1), "=&D" (ignore2), "=m" (futex), \
321 "=a" (result) \
322 : "0" (id | FUTEX_WAITERS), "m" (futex), "3" (0) \
323 : "cx", "r11", "cc", "memory"); \
324 result; })
325
326
327 #define lll_mutex_timedlock(futex, timeout) \
328 ({ int result, ignore1, ignore2, ignore3; \
329 __asm __volatile (LOCK_INSTR "cmpxchgl %2, %4\n\t" \
330 "jnz 1f\n\t" \
331 ".subsection 1\n\t" \
332 ".type _L_mutex_timedlock_%=, @function\n" \
333 "_L_mutex_timedlock_%=:\n" \
334 "1:\tleaq %4, %%rdi\n" \
335 "0:\tmovq %8, %%rdx\n" \
336 "2:\tsubq $128, %%rsp\n" \
337 "3:\tcallq __lll_mutex_timedlock_wait\n" \
338 "4:\taddq $128, %%rsp\n" \
339 "5:\tjmp 24f\n" \
340 "6:\t.size _L_mutex_timedlock_%=, 6b-1b\n\t" \
341 ".previous\n" \
342 LLL_STUB_UNWIND_INFO_6 \
343 "24:" \
344 : "=a" (result), "=&D" (ignore1), "=S" (ignore2), \
345 "=&d" (ignore3), "=m" (futex) \
346 : "0" (0), "2" (1), "m" (futex), "m" (timeout) \
347 : "memory", "cx", "cc", "r10", "r11"); \
348 result; })
349
350
351 #define lll_robust_mutex_timedlock(futex, timeout, id) \
352 ({ int result, ignore1, ignore2, ignore3; \
353 __asm __volatile (LOCK_INSTR "cmpxchgl %2, %4\n\t" \
354 "jnz 1f\n\t" \
355 ".subsection 1\n\t" \
356 ".type _L_robust_mutex_timedlock_%=, @function\n" \
357 "_L_robust_mutex_timedlock_%=:\n" \
358 "1:\tleaq %4, %%rdi\n" \
359 "0:\tmovq %8, %%rdx\n" \
360 "2:\tsubq $128, %%rsp\n" \
361 "3:\tcallq __lll_robust_mutex_timedlock_wait\n" \
362 "4:\taddq $128, %%rsp\n" \
363 "5:\tjmp 24f\n" \
364 "6:\t.size _L_robust_mutex_timedlock_%=, 6b-1b\n\t" \
365 ".previous\n" \
366 LLL_STUB_UNWIND_INFO_6 \
367 "24:" \
368 : "=a" (result), "=&D" (ignore1), "=S" (ignore2), \
369 "=&d" (ignore3), "=m" (futex) \
370 : "0" (0), "2" (id), "m" (futex), "m" (timeout) \
371 : "memory", "cx", "cc", "r10", "r11"); \
372 result; })
373
374
375 #define lll_mutex_unlock(futex) \
376 (void) ({ int ignore; \
377 __asm __volatile (LOCK_INSTR "decl %0\n\t" \
378 "jne 1f\n\t" \
379 ".subsection 1\n\t" \
380 ".type _L_mutex_unlock_%=, @function\n" \
381 "_L_mutex_unlock_%=:\n" \
382 "1:\tleaq %0, %%rdi\n" \
383 "2:\tsubq $128, %%rsp\n" \
384 "3:\tcallq __lll_mutex_unlock_wake\n" \
385 "4:\taddq $128, %%rsp\n" \
386 "5:\tjmp 24f\n" \
387 "6:\t.size _L_mutex_unlock_%=, 6b-1b\n\t" \
388 ".previous\n" \
389 LLL_STUB_UNWIND_INFO_5 \
390 "24:" \
391 : "=m" (futex), "=&D" (ignore) \
392 : "m" (futex) \
393 : "ax", "cx", "r11", "cc", "memory"); })
394
395
396 #define lll_robust_mutex_unlock(futex) \
397 (void) ({ int ignore; \
398 __asm __volatile (LOCK_INSTR "andl %2, %0\n\t" \
399 "jne 1f\n\t" \
400 ".subsection 1\n\t" \
401 ".type _L_robust_mutex_unlock_%=, @function\n" \
402 "_L_robust_mutex_unlock_%=:\n" \
403 "1:\tleaq %0, %%rdi\n" \
404 "2:\tsubq $128, %%rsp\n" \
405 "3:\tcallq __lll_mutex_unlock_wake\n" \
406 "4:\taddq $128, %%rsp\n" \
407 "5:\tjmp 24f\n" \
408 "6:\t.size _L_robust_mutex_unlock_%=, 6b-1b\n\t"\
409 ".previous\n" \
410 LLL_STUB_UNWIND_INFO_5 \
411 "24:" \
412 : "=m" (futex), "=&D" (ignore) \
413 : "i" (FUTEX_WAITERS), "m" (futex) \
414 : "ax", "cx", "r11", "cc", "memory"); })
415
416
417 #define lll_robust_mutex_dead(futex) \
418 (void) ({ int ignore; \
419 __asm __volatile (LOCK_INSTR "orl %3, (%2)\n\t" \
420 "syscall" \
421 : "=m" (futex), "=a" (ignore) \
422 : "D" (&(futex)), "i" (FUTEX_OWNER_DIED), \
423 "S" (FUTEX_WAKE), "1" (__NR_futex), \
424 "d" (1) \
425 : "cx", "r11", "cc", "memory"); })
426
427
428 /* Returns non-zero if error happened, zero if success. */
429 #define lll_futex_requeue(ftx, nr_wake, nr_move, mutex, val) \
430 ({ int __res; \
431 register int __nr_move __asm ("r10") = nr_move; \
432 register void *__mutex __asm ("r8") = mutex; \
433 register int __val __asm ("r9") = val; \
434 __asm __volatile ("syscall" \
435 : "=a" (__res) \
436 : "0" (__NR_futex), "D" ((void *) ftx), \
437 "S" (FUTEX_CMP_REQUEUE), "d" (nr_wake), \
438 "r" (__nr_move), "r" (__mutex), "r" (__val) \
439 : "cx", "r11", "cc", "memory"); \
440 __res < 0; })
441
442
443 #define lll_mutex_islocked(futex) \
444 (futex != LLL_MUTEX_LOCK_INITIALIZER)
445
446
447 /* We have a separate internal lock implementation which is not tied
448 to binary compatibility. */
449
450 /* Type for lock object. */
451 typedef int lll_lock_t;
452
453 /* Initializers for lock. */
454 #define LLL_LOCK_INITIALIZER (0)
455 #define LLL_LOCK_INITIALIZER_LOCKED (1)
456
457
458 /* The states of a lock are:
459 0 - untaken
460 1 - taken by one user
461 2 - taken by more users */
462
463
464 #if defined NOT_IN_libc || defined UP
465 # define lll_trylock(futex) lll_mutex_trylock (futex)
466 # define lll_lock(futex) lll_mutex_lock (futex)
467 # define lll_unlock(futex) lll_mutex_unlock (futex)
468 #else
469 /* Special versions of the macros for use in libc itself. They avoid
470 the lock prefix when the thread library is not used.
471
472 The code sequence to avoid unnecessary lock prefixes is what the AMD
473 guys suggested. If you do not like it, bring it up with AMD.
474
475 XXX In future we might even want to avoid it on UP machines. */
476
477 # define lll_trylock(futex) \
478 ({ unsigned char ret; \
479 __asm __volatile ("cmpl $0, __libc_multiple_threads(%%rip)\n\t" \
480 "je 0f\n\t" \
481 "lock; cmpxchgl %2, %1\n\t" \
482 "jmp 1f\n" \
483 "0:\tcmpxchgl %2, %1\n\t" \
484 "1:setne %0" \
485 : "=a" (ret), "=m" (futex) \
486 : "r" (LLL_MUTEX_LOCK_INITIALIZER_LOCKED), "m" (futex),\
487 "0" (LLL_MUTEX_LOCK_INITIALIZER) \
488 : "memory"); \
489 ret; })
490
491
492 # define lll_lock(futex) \
493 (void) ({ int ignore1, ignore2, ignore3; \
494 __asm __volatile ("cmpl $0, __libc_multiple_threads(%%rip)\n\t" \
495 "je 0f\n\t" \
496 "lock; cmpxchgl %0, %2\n\t" \
497 "jnz 1f\n\t" \
498 "jmp 24f\n" \
499 "0:\tcmpxchgl %0, %2\n\t" \
500 "jnz 1f\n\t" \
501 ".subsection 1\n\t" \
502 ".type _L_lock_%=, @function\n" \
503 "_L_lock_%=:\n" \
504 "1:\tleaq %2, %%rdi\n" \
505 "2:\tsubq $128, %%rsp\n" \
506 "3:\tcallq __lll_mutex_lock_wait\n" \
507 "4:\taddq $128, %%rsp\n" \
508 "5:\tjmp 24f\n" \
509 "6:\t.size _L_lock_%=, 6b-1b\n\t" \
510 ".previous\n" \
511 LLL_STUB_UNWIND_INFO_5 \
512 "24:" \
513 : "=S" (ignore1), "=&D" (ignore2), "=m" (futex),\
514 "=a" (ignore3) \
515 : "0" (1), "m" (futex), "3" (0) \
516 : "cx", "r11", "cc", "memory"); })
517
518
519 # define lll_unlock(futex) \
520 (void) ({ int ignore; \
521 __asm __volatile ("cmpl $0, __libc_multiple_threads(%%rip)\n\t" \
522 "je 0f\n\t" \
523 "lock; decl %0\n\t" \
524 "jne 1f\n\t" \
525 "jmp 24f\n" \
526 "0:\tdecl %0\n\t" \
527 "jne 1f\n\t" \
528 ".subsection 1\n\t" \
529 ".type _L_unlock_%=, @function\n" \
530 "_L_unlock_%=:\n" \
531 "1:\tleaq %0, %%rdi\n" \
532 "2:\tsubq $128, %%rsp\n" \
533 "3:\tcallq __lll_mutex_unlock_wake\n" \
534 "4:\taddq $128, %%rsp\n" \
535 "5:\tjmp 24f\n" \
536 "6:\t.size _L_unlock_%=, 6b-1b\n\t" \
537 ".previous\n" \
538 LLL_STUB_UNWIND_INFO_5 \
539 "24:" \
540 : "=m" (futex), "=&D" (ignore) \
541 : "m" (futex) \
542 : "ax", "cx", "r11", "cc", "memory"); })
543 #endif
544
545
546 #define lll_islocked(futex) \
547 (futex != LLL_MUTEX_LOCK_INITIALIZER)
548
549
550 /* The kernel notifies a process with uses CLONE_CLEARTID via futex
551 wakeup when the clone terminates. The memory location contains the
552 thread ID while the clone is running and is reset to zero
553 afterwards.
554
555 The macro parameter must not have any side effect. */
556 #define lll_wait_tid(tid) \
557 do { \
558 int __ignore; \
559 register __typeof (tid) _tid asm ("edx") = (tid); \
560 if (_tid != 0) \
561 __asm __volatile ("xorq %%r10, %%r10\n\t" \
562 "1:\tmovq %2, %%rax\n\t" \
563 "syscall\n\t" \
564 "cmpl $0, (%%rdi)\n\t" \
565 "jne 1b" \
566 : "=&a" (__ignore) \
567 : "S" (FUTEX_WAIT), "i" (SYS_futex), "D" (&tid), \
568 "d" (_tid) \
569 : "memory", "cc", "r10", "r11", "cx"); \
570 } while (0)
571
572 extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime)
573 attribute_hidden;
574 #define lll_timedwait_tid(tid, abstime) \
575 ({ \
576 int __result = 0; \
577 if (tid != 0) \
578 { \
579 if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) \
580 __result = EINVAL; \
581 else \
582 __result = __lll_timedwait_tid (&tid, abstime); \
583 } \
584 __result; })
585
586
587 /* Conditional variable handling. */
588
589 extern void __lll_cond_wait (pthread_cond_t *cond) attribute_hidden;
590 extern int __lll_cond_timedwait (pthread_cond_t *cond,
591 const struct timespec *abstime)
592 attribute_hidden;
593 extern void __lll_cond_wake (pthread_cond_t *cond) attribute_hidden;
594 extern void __lll_cond_broadcast (pthread_cond_t *cond) attribute_hidden;
595
596
597 #define lll_cond_wait(cond) \
598 __lll_cond_wait (cond)
599 #define lll_cond_timedwait(cond, abstime) \
600 __lll_cond_timedwait (cond, abstime)
601 #define lll_cond_wake(cond) \
602 __lll_cond_wake (cond)
603 #define lll_cond_broadcast(cond) \
604 __lll_cond_broadcast (cond)
605
606
607 #endif /* lowlevellock.h */