]>
Commit | Line | Data |
---|---|---|
7dd650d7 | 1 | /* Copyright (C) 2002-2004, 2006-2008, 2009 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 | ||
e51deae7 UD |
23 | #ifndef __ASSEMBLER__ |
24 | # include <time.h> | |
25 | # include <sys/param.h> | |
26 | # include <bits/pthreadtypes.h> | |
27 | # include <kernel-features.h> | |
28 | # include <tcb-offsets.h> | |
29 | ||
30 | # ifndef LOCK_INSTR | |
31 | # ifdef UP | |
32 | # define LOCK_INSTR /* nothing */ | |
33 | # else | |
34 | # define LOCK_INSTR "lock;" | |
35 | # endif | |
36 | # endif | |
37 | #else | |
38 | # ifndef LOCK | |
39 | # ifdef UP | |
40 | # define LOCK | |
41 | # else | |
42 | # define LOCK lock | |
43 | # endif | |
76a50749 UD |
44 | # endif |
45 | #endif | |
46 | ||
47 | #define SYS_futex 240 | |
48 | #define FUTEX_WAIT 0 | |
49 | #define FUTEX_WAKE 1 | |
e51deae7 UD |
50 | #define FUTEX_CMP_REQUEUE 4 |
51 | #define FUTEX_WAKE_OP 5 | |
d5ba53f9 UD |
52 | #define FUTEX_LOCK_PI 6 |
53 | #define FUTEX_UNLOCK_PI 7 | |
54 | #define FUTEX_TRYLOCK_PI 8 | |
da5ac135 UD |
55 | #define FUTEX_WAIT_BITSET 9 |
56 | #define FUTEX_WAKE_BITSET 10 | |
75956694 DG |
57 | #define FUTEX_WAIT_REQUEUE_PI 11 |
58 | #define FUTEX_CMP_REQUEUE_PI 12 | |
5a8075b1 | 59 | #define FUTEX_PRIVATE_FLAG 128 |
7dd650d7 UD |
60 | #define FUTEX_CLOCK_REALTIME 256 |
61 | ||
62 | #define FUTEX_BITSET_MATCH_ANY 0xffffffff | |
76a50749 | 63 | |
e51deae7 | 64 | #define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE ((4 << 24) | 1) |
76a50749 | 65 | |
835abc5c UD |
66 | /* Values for 'private' parameter of locking macros. Yes, the |
67 | definition seems to be backwards. But it is not. The bit will be | |
68 | reversed before passing to the system call. */ | |
69 | #define LLL_PRIVATE 0 | |
70 | #define LLL_SHARED FUTEX_PRIVATE_FLAG | |
71 | ||
72 | ||
1168be45 JJ |
73 | #if !defined NOT_IN_libc || defined IS_IN_rtld |
74 | /* In libc.so or ld.so all futexes are private. */ | |
75 | # ifdef __ASSUME_PRIVATE_FUTEX | |
76 | # define __lll_private_flag(fl, private) \ | |
77 | ((fl) | FUTEX_PRIVATE_FLAG) | |
78 | # else | |
79 | # define __lll_private_flag(fl, private) \ | |
80 | ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex)) | |
81 | # endif | |
82 | #else | |
83 | # ifdef __ASSUME_PRIVATE_FUTEX | |
84 | # define __lll_private_flag(fl, private) \ | |
85 | (((fl) | FUTEX_PRIVATE_FLAG) ^ (private)) | |
86 | # else | |
87 | # define __lll_private_flag(fl, private) \ | |
88 | (__builtin_constant_p (private) \ | |
89 | ? ((private) == 0 \ | |
90 | ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex)) \ | |
91 | : (fl)) \ | |
92 | : ({ unsigned int __fl = ((private) ^ FUTEX_PRIVATE_FLAG); \ | |
22502ea2 | 93 | asm ("andl %%gs:%P1, %0" : "+r" (__fl) \ |
1168be45 JJ |
94 | : "i" (offsetof (struct pthread, header.private_futex))); \ |
95 | __fl | (fl); })) | |
da5ac135 | 96 | # endif |
1168be45 JJ |
97 | #endif |
98 | ||
e51deae7 | 99 | #ifndef __ASSEMBLER__ |
1168be45 | 100 | |
76a50749 | 101 | /* Initializer for compatibility lock. */ |
e51deae7 UD |
102 | #define LLL_LOCK_INITIALIZER (0) |
103 | #define LLL_LOCK_INITIALIZER_LOCKED (1) | |
104 | #define LLL_LOCK_INITIALIZER_WAITERS (2) | |
76a50749 UD |
105 | |
106 | ||
949ec764 UD |
107 | #ifdef PIC |
108 | # define LLL_EBX_LOAD "xchgl %2, %%ebx\n" | |
109 | # define LLL_EBX_REG "D" | |
110 | #else | |
111 | # define LLL_EBX_LOAD | |
112 | # define LLL_EBX_REG "b" | |
113 | #endif | |
114 | ||
115 | #ifdef I386_USE_SYSENTER | |
116 | # ifdef SHARED | |
20945457 | 117 | # define LLL_ENTER_KERNEL "call *%%gs:%P6\n\t" |
949ec764 | 118 | # else |
20945457 | 119 | # define LLL_ENTER_KERNEL "call *_dl_sysinfo\n\t" |
949ec764 UD |
120 | # endif |
121 | #else | |
122 | # define LLL_ENTER_KERNEL "int $0x80\n\t" | |
123 | #endif | |
124 | ||
2c0b891a | 125 | /* Delay in spinlock loop. */ |
e51deae7 | 126 | #define BUSY_WAIT_NOP asm ("rep; nop") |
2c0b891a | 127 | |
92d83c72 | 128 | |
cd248c3f UD |
129 | #define LLL_STUB_UNWIND_INFO_START \ |
130 | ".section .eh_frame,\"a\",@progbits\n" \ | |
131 | "5:\t" ".long 7f-6f # Length of Common Information Entry\n" \ | |
132 | "6:\t" ".long 0x0 # CIE Identifier Tag\n\t" \ | |
133 | ".byte 0x1 # CIE Version\n\t" \ | |
134 | ".ascii \"zR\\0\" # CIE Augmentation\n\t" \ | |
135 | ".uleb128 0x1 # CIE Code Alignment Factor\n\t" \ | |
136 | ".sleb128 -4 # CIE Data Alignment Factor\n\t" \ | |
137 | ".byte 0x8 # CIE RA Column\n\t" \ | |
138 | ".uleb128 0x1 # Augmentation size\n\t" \ | |
139 | ".byte 0x1b # FDE Encoding (pcrel sdata4)\n\t" \ | |
140 | ".byte 0xc # DW_CFA_def_cfa\n\t" \ | |
141 | ".uleb128 0x4\n\t" \ | |
142 | ".uleb128 0x0\n\t" \ | |
143 | ".align 4\n" \ | |
144 | "7:\t" ".long 17f-8f # FDE Length\n" \ | |
145 | "8:\t" ".long 8b-5b # FDE CIE offset\n\t" \ | |
146 | ".long 1b-. # FDE initial location\n\t" \ | |
147 | ".long 4b-1b # FDE address range\n\t" \ | |
148 | ".uleb128 0x0 # Augmentation size\n\t" \ | |
149 | ".byte 0x16 # DW_CFA_val_expression\n\t" \ | |
150 | ".uleb128 0x8\n\t" \ | |
151 | ".uleb128 10f-9f\n" \ | |
152 | "9:\t" ".byte 0x78 # DW_OP_breg8\n\t" \ | |
153 | ".sleb128 3b-1b\n" | |
154 | #define LLL_STUB_UNWIND_INFO_END \ | |
155 | ".byte 0x16 # DW_CFA_val_expression\n\t" \ | |
156 | ".uleb128 0x8\n\t" \ | |
157 | ".uleb128 12f-11f\n" \ | |
158 | "11:\t" ".byte 0x78 # DW_OP_breg8\n\t" \ | |
159 | ".sleb128 3b-2b\n" \ | |
160 | "12:\t" ".byte 0x40 + (3b-2b-1) # DW_CFA_advance_loc\n\t" \ | |
161 | ".byte 0x16 # DW_CFA_val_expression\n\t" \ | |
162 | ".uleb128 0x8\n\t" \ | |
163 | ".uleb128 16f-13f\n" \ | |
164 | "13:\t" ".byte 0x78 # DW_OP_breg8\n\t" \ | |
165 | ".sleb128 15f-14f\n\t" \ | |
166 | ".byte 0x0d # DW_OP_const4s\n" \ | |
167 | "14:\t" ".4byte 3b-.\n\t" \ | |
168 | ".byte 0x1c # DW_OP_minus\n\t" \ | |
169 | ".byte 0x0d # DW_OP_const4s\n" \ | |
170 | "15:\t" ".4byte 18f-.\n\t" \ | |
171 | ".byte 0x22 # DW_OP_plus\n" \ | |
172 | "16:\t" ".align 4\n" \ | |
173 | "17:\t" ".previous\n" | |
174 | ||
175 | /* Unwind info for | |
176 | 1: lea ..., ... | |
177 | 2: call ... | |
178 | 3: jmp 18f | |
179 | 4: | |
180 | snippet. */ | |
181 | #define LLL_STUB_UNWIND_INFO_3 \ | |
182 | LLL_STUB_UNWIND_INFO_START \ | |
183 | "10:\t" ".byte 0x40 + (2b-1b) # DW_CFA_advance_loc\n\t" \ | |
184 | LLL_STUB_UNWIND_INFO_END | |
185 | ||
186 | /* Unwind info for | |
187 | 1: lea ..., ... | |
188 | 0: movl ..., ... | |
189 | 2: call ... | |
190 | 3: jmp 18f | |
191 | 4: | |
192 | snippet. */ | |
193 | #define LLL_STUB_UNWIND_INFO_4 \ | |
194 | LLL_STUB_UNWIND_INFO_START \ | |
195 | "10:\t" ".byte 0x40 + (0b-1b) # DW_CFA_advance_loc\n\t" \ | |
196 | ".byte 0x16 # DW_CFA_val_expression\n\t" \ | |
197 | ".uleb128 0x8\n\t" \ | |
198 | ".uleb128 20f-19f\n" \ | |
199 | "19:\t" ".byte 0x78 # DW_OP_breg8\n\t" \ | |
200 | ".sleb128 3b-0b\n" \ | |
201 | "20:\t" ".byte 0x40 + (2b-0b) # DW_CFA_advance_loc\n\t" \ | |
202 | LLL_STUB_UNWIND_INFO_END | |
203 | ||
204 | ||
835abc5c UD |
205 | #define lll_futex_wait(futex, val, private) \ |
206 | lll_futex_timed_wait (futex, val, NULL, private) | |
207 | ||
208 | ||
209 | #define lll_futex_timed_wait(futex, val, timeout, private) \ | |
679d83ba UD |
210 | ({ \ |
211 | int __status; \ | |
92d83c72 | 212 | register __typeof (val) _val asm ("edx") = (val); \ |
949ec764 | 213 | __asm __volatile (LLL_EBX_LOAD \ |
92d83c72 | 214 | LLL_ENTER_KERNEL \ |
949ec764 | 215 | LLL_EBX_LOAD \ |
679d83ba | 216 | : "=a" (__status) \ |
835abc5c | 217 | : "0" (SYS_futex), LLL_EBX_REG (futex), "S" (timeout), \ |
1168be45 JJ |
218 | "c" (__lll_private_flag (FUTEX_WAIT, private)), \ |
219 | "d" (_val), "i" (offsetof (tcbhead_t, sysinfo)) \ | |
b576fca1 | 220 | : "memory"); \ |
679d83ba UD |
221 | __status; \ |
222 | }) | |
223 | ||
224 | ||
835abc5c UD |
225 | #define lll_futex_wake(futex, nr, private) \ |
226 | do { \ | |
227 | int __ignore; \ | |
228 | register __typeof (nr) _nr asm ("edx") = (nr); \ | |
229 | __asm __volatile (LLL_EBX_LOAD \ | |
230 | LLL_ENTER_KERNEL \ | |
231 | LLL_EBX_LOAD \ | |
232 | : "=a" (__ignore) \ | |
233 | : "0" (SYS_futex), LLL_EBX_REG (futex), \ | |
1168be45 JJ |
234 | "c" (__lll_private_flag (FUTEX_WAKE, private)), \ |
235 | "d" (_nr), \ | |
949ec764 | 236 | "i" (0) /* phony, to align next arg's number */, \ |
92d83c72 UD |
237 | "i" (offsetof (tcbhead_t, sysinfo))); \ |
238 | } while (0) | |
239 | ||
240 | ||
e51deae7 | 241 | /* NB: in the lll_trylock macro we simply return the value in %eax |
e408880b UD |
242 | after the cmpxchg instruction. In case the operation succeded this |
243 | value is zero. In case the operation failed, the cmpxchg instruction | |
244 | has loaded the current value of the memory work which is guaranteed | |
245 | to be nonzero. */ | |
e51deae7 UD |
246 | #if defined NOT_IN_libc || defined UP |
247 | # define __lll_trylock_asm LOCK_INSTR "cmpxchgl %2, %1" | |
248 | #else | |
249 | # define __lll_trylock_asm "cmpl $0, %%gs:%P5\n\t" \ | |
250 | "je 0f\n\t" \ | |
251 | "lock\n" \ | |
252 | "0:\tcmpxchgl %2, %1" | |
253 | #endif | |
254 | ||
255 | #define lll_trylock(futex) \ | |
e408880b | 256 | ({ int ret; \ |
e51deae7 | 257 | __asm __volatile (__lll_trylock_asm \ |
76a50749 | 258 | : "=a" (ret), "=m" (futex) \ |
e51deae7 UD |
259 | : "r" (LLL_LOCK_INITIALIZER_LOCKED), "m" (futex), \ |
260 | "0" (LLL_LOCK_INITIALIZER), \ | |
261 | "i" (MULTIPLE_THREADS_OFFSET) \ | |
7a5cdb30 | 262 | : "memory"); \ |
76a50749 UD |
263 | ret; }) |
264 | ||
e51deae7 | 265 | #define lll_robust_trylock(futex, id) \ |
683040c3 UD |
266 | ({ int ret; \ |
267 | __asm __volatile (LOCK_INSTR "cmpxchgl %2, %1" \ | |
268 | : "=a" (ret), "=m" (futex) \ | |
269 | : "r" (id), "m" (futex), \ | |
e51deae7 | 270 | "0" (LLL_LOCK_INITIALIZER) \ |
683040c3 UD |
271 | : "memory"); \ |
272 | ret; }) | |
273 | ||
274 | ||
e51deae7 | 275 | #define lll_cond_trylock(futex) \ |
2c0b891a UD |
276 | ({ int ret; \ |
277 | __asm __volatile (LOCK_INSTR "cmpxchgl %2, %1" \ | |
278 | : "=a" (ret), "=m" (futex) \ | |
e51deae7 UD |
279 | : "r" (LLL_LOCK_INITIALIZER_WAITERS), \ |
280 | "m" (futex), "0" (LLL_LOCK_INITIALIZER) \ | |
2c0b891a UD |
281 | : "memory"); \ |
282 | ret; }) | |
283 | ||
e51deae7 UD |
284 | #if defined NOT_IN_libc || defined UP |
285 | # define __lll_lock_asm_start LOCK_INSTR "cmpxchgl %1, %2\n\t" | |
286 | #else | |
287 | # define __lll_lock_asm_start "cmpl $0, %%gs:%P6\n\t" \ | |
288 | "je 0f\n\t" \ | |
289 | "lock\n" \ | |
290 | "0:\tcmpxchgl %1, %2\n\t" | |
291 | #endif | |
2c0b891a | 292 | |
e51deae7 UD |
293 | #define lll_lock(futex, private) \ |
294 | (void) \ | |
295 | ({ int ignore1, ignore2; \ | |
296 | if (__builtin_constant_p (private) && (private) == LLL_PRIVATE) \ | |
297 | __asm __volatile (__lll_lock_asm_start \ | |
298 | "jnz _L_lock_%=\n\t" \ | |
299 | ".subsection 1\n\t" \ | |
300 | ".type _L_lock_%=,@function\n" \ | |
301 | "_L_lock_%=:\n" \ | |
302 | "1:\tleal %2, %%ecx\n" \ | |
303 | "2:\tcall __lll_lock_wait_private\n" \ | |
304 | "3:\tjmp 18f\n" \ | |
305 | "4:\t.size _L_lock_%=, 4b-1b\n\t" \ | |
306 | ".previous\n" \ | |
307 | LLL_STUB_UNWIND_INFO_3 \ | |
308 | "18:" \ | |
309 | : "=a" (ignore1), "=c" (ignore2), "=m" (futex) \ | |
310 | : "0" (0), "1" (1), "m" (futex), \ | |
311 | "i" (MULTIPLE_THREADS_OFFSET) \ | |
312 | : "memory"); \ | |
313 | else \ | |
314 | { \ | |
315 | int ignore3; \ | |
316 | __asm __volatile (__lll_lock_asm_start \ | |
317 | "jnz _L_lock_%=\n\t" \ | |
318 | ".subsection 1\n\t" \ | |
319 | ".type _L_lock_%=,@function\n" \ | |
320 | "_L_lock_%=:\n" \ | |
321 | "1:\tleal %2, %%edx\n" \ | |
322 | "0:\tmovl %8, %%ecx\n" \ | |
323 | "2:\tcall __lll_lock_wait\n" \ | |
324 | "3:\tjmp 18f\n" \ | |
325 | "4:\t.size _L_lock_%=, 4b-1b\n\t" \ | |
326 | ".previous\n" \ | |
327 | LLL_STUB_UNWIND_INFO_4 \ | |
328 | "18:" \ | |
329 | : "=a" (ignore1), "=c" (ignore2), \ | |
330 | "=m" (futex), "=&d" (ignore3) \ | |
331 | : "1" (1), "m" (futex), \ | |
332 | "i" (MULTIPLE_THREADS_OFFSET), "0" (0), \ | |
2458c748 | 333 | "g" ((int) (private)) \ |
e51deae7 UD |
334 | : "memory"); \ |
335 | } \ | |
336 | }) | |
337 | ||
338 | #define lll_robust_lock(futex, id, private) \ | |
339 | ({ int result, ignore1, ignore2; \ | |
683040c3 | 340 | __asm __volatile (LOCK_INSTR "cmpxchgl %1, %2\n\t" \ |
e51deae7 | 341 | "jnz _L_robust_lock_%=\n\t" \ |
683040c3 | 342 | ".subsection 1\n\t" \ |
e51deae7 UD |
343 | ".type _L_robust_lock_%=,@function\n" \ |
344 | "_L_robust_lock_%=:\n" \ | |
345 | "1:\tleal %2, %%edx\n" \ | |
346 | "0:\tmovl %7, %%ecx\n" \ | |
347 | "2:\tcall __lll_robust_lock_wait\n" \ | |
cd248c3f | 348 | "3:\tjmp 18f\n" \ |
e51deae7 | 349 | "4:\t.size _L_robust_lock_%=, 4b-1b\n\t" \ |
683040c3 | 350 | ".previous\n" \ |
e51deae7 | 351 | LLL_STUB_UNWIND_INFO_4 \ |
cd248c3f | 352 | "18:" \ |
e51deae7 UD |
353 | : "=a" (result), "=c" (ignore1), "=m" (futex), \ |
354 | "=&d" (ignore2) \ | |
2458c748 | 355 | : "0" (0), "1" (id), "m" (futex), "g" ((int) (private))\ |
683040c3 UD |
356 | : "memory"); \ |
357 | result; }) | |
358 | ||
359 | ||
e51deae7 | 360 | /* Special version of lll_lock which causes the unlock function to |
69431c9a | 361 | always wakeup waiters. */ |
e51deae7 UD |
362 | #define lll_cond_lock(futex, private) \ |
363 | (void) \ | |
364 | ({ int ignore1, ignore2, ignore3; \ | |
365 | __asm __volatile (LOCK_INSTR "cmpxchgl %1, %2\n\t" \ | |
366 | "jnz _L_cond_lock_%=\n\t" \ | |
367 | ".subsection 1\n\t" \ | |
368 | ".type _L_cond_lock_%=,@function\n" \ | |
369 | "_L_cond_lock_%=:\n" \ | |
370 | "1:\tleal %2, %%edx\n" \ | |
371 | "0:\tmovl %7, %%ecx\n" \ | |
372 | "2:\tcall __lll_lock_wait\n" \ | |
373 | "3:\tjmp 18f\n" \ | |
374 | "4:\t.size _L_cond_lock_%=, 4b-1b\n\t" \ | |
375 | ".previous\n" \ | |
376 | LLL_STUB_UNWIND_INFO_4 \ | |
377 | "18:" \ | |
378 | : "=a" (ignore1), "=c" (ignore2), "=m" (futex), \ | |
379 | "=&d" (ignore3) \ | |
2458c748 | 380 | : "0" (0), "1" (2), "m" (futex), "g" ((int) (private))\ |
e51deae7 UD |
381 | : "memory"); \ |
382 | }) | |
383 | ||
384 | ||
385 | #define lll_robust_cond_lock(futex, id, private) \ | |
386 | ({ int result, ignore1, ignore2; \ | |
683040c3 | 387 | __asm __volatile (LOCK_INSTR "cmpxchgl %1, %2\n\t" \ |
e51deae7 | 388 | "jnz _L_robust_cond_lock_%=\n\t" \ |
683040c3 | 389 | ".subsection 1\n\t" \ |
e51deae7 UD |
390 | ".type _L_robust_cond_lock_%=,@function\n" \ |
391 | "_L_robust_cond_lock_%=:\n" \ | |
392 | "1:\tleal %2, %%edx\n" \ | |
393 | "0:\tmovl %7, %%ecx\n" \ | |
394 | "2:\tcall __lll_robust_lock_wait\n" \ | |
cd248c3f | 395 | "3:\tjmp 18f\n" \ |
e51deae7 | 396 | "4:\t.size _L_robust_cond_lock_%=, 4b-1b\n\t" \ |
683040c3 | 397 | ".previous\n" \ |
e51deae7 | 398 | LLL_STUB_UNWIND_INFO_4 \ |
cd248c3f | 399 | "18:" \ |
e51deae7 UD |
400 | : "=a" (result), "=c" (ignore1), "=m" (futex), \ |
401 | "=&d" (ignore2) \ | |
402 | : "0" (0), "1" (id | FUTEX_WAITERS), "m" (futex), \ | |
2458c748 | 403 | "g" ((int) (private)) \ |
683040c3 UD |
404 | : "memory"); \ |
405 | result; }) | |
406 | ||
407 | ||
e51deae7 UD |
408 | #define lll_timedlock(futex, timeout, private) \ |
409 | ({ int result, ignore1, ignore2, ignore3; \ | |
71451de2 | 410 | __asm __volatile (LOCK_INSTR "cmpxchgl %1, %3\n\t" \ |
e51deae7 | 411 | "jnz _L_timedlock_%=\n\t" \ |
8348dcc8 | 412 | ".subsection 1\n\t" \ |
e51deae7 UD |
413 | ".type _L_timedlock_%=,@function\n" \ |
414 | "_L_timedlock_%=:\n" \ | |
cd248c3f | 415 | "1:\tleal %3, %%ecx\n" \ |
e51deae7 UD |
416 | "0:\tmovl %8, %%edx\n" \ |
417 | "2:\tcall __lll_timedlock_wait\n" \ | |
cd248c3f | 418 | "3:\tjmp 18f\n" \ |
e51deae7 | 419 | "4:\t.size _L_timedlock_%=, 4b-1b\n\t" \ |
7a5cdb30 | 420 | ".previous\n" \ |
cd248c3f UD |
421 | LLL_STUB_UNWIND_INFO_4 \ |
422 | "18:" \ | |
71451de2 | 423 | : "=a" (result), "=c" (ignore1), "=&d" (ignore2), \ |
e51deae7 UD |
424 | "=m" (futex), "=S" (ignore3) \ |
425 | : "0" (0), "1" (1), "m" (futex), "m" (timeout), \ | |
2458c748 | 426 | "4" ((int) (private)) \ |
7a5cdb30 | 427 | : "memory"); \ |
76a50749 UD |
428 | result; }) |
429 | ||
430 | ||
e51deae7 UD |
431 | #define lll_robust_timedlock(futex, timeout, id, private) \ |
432 | ({ int result, ignore1, ignore2, ignore3; \ | |
683040c3 | 433 | __asm __volatile (LOCK_INSTR "cmpxchgl %1, %3\n\t" \ |
e51deae7 | 434 | "jnz _L_robust_timedlock_%=\n\t" \ |
683040c3 | 435 | ".subsection 1\n\t" \ |
e51deae7 UD |
436 | ".type _L_robust_timedlock_%=,@function\n" \ |
437 | "_L_robust_timedlock_%=:\n" \ | |
cd248c3f | 438 | "1:\tleal %3, %%ecx\n" \ |
e51deae7 UD |
439 | "0:\tmovl %8, %%edx\n" \ |
440 | "2:\tcall __lll_robust_timedlock_wait\n" \ | |
cd248c3f | 441 | "3:\tjmp 18f\n" \ |
e51deae7 | 442 | "4:\t.size _L_robust_timedlock_%=, 4b-1b\n\t" \ |
683040c3 | 443 | ".previous\n" \ |
cd248c3f UD |
444 | LLL_STUB_UNWIND_INFO_4 \ |
445 | "18:" \ | |
683040c3 | 446 | : "=a" (result), "=c" (ignore1), "=&d" (ignore2), \ |
e51deae7 UD |
447 | "=m" (futex), "=S" (ignore3) \ |
448 | : "0" (0), "1" (id), "m" (futex), "m" (timeout), \ | |
2458c748 | 449 | "4" ((int) (private)) \ |
683040c3 UD |
450 | : "memory"); \ |
451 | result; }) | |
452 | ||
14e7aece | 453 | #if defined NOT_IN_libc || defined UP |
e51deae7 | 454 | # define __lll_unlock_asm LOCK_INSTR "subl $1, %0\n\t" |
14e7aece | 455 | #else |
e51deae7 UD |
456 | # define __lll_unlock_asm "cmpl $0, %%gs:%P3\n\t" \ |
457 | "je 0f\n\t" \ | |
458 | "lock\n" \ | |
459 | "0:\tsubl $1,%0\n\t" | |
14e7aece | 460 | #endif |
76a50749 | 461 | |
e51deae7 UD |
462 | #define lll_unlock(futex, private) \ |
463 | (void) \ | |
464 | ({ int ignore; \ | |
465 | if (__builtin_constant_p (private) && (private) == LLL_PRIVATE) \ | |
466 | __asm __volatile (__lll_unlock_asm \ | |
467 | "jne _L_unlock_%=\n\t" \ | |
468 | ".subsection 1\n\t" \ | |
469 | ".type _L_unlock_%=,@function\n" \ | |
470 | "_L_unlock_%=:\n" \ | |
471 | "1:\tleal %0, %%eax\n" \ | |
472 | "2:\tcall __lll_unlock_wake_private\n" \ | |
473 | "3:\tjmp 18f\n" \ | |
474 | "4:\t.size _L_unlock_%=, 4b-1b\n\t" \ | |
475 | ".previous\n" \ | |
476 | LLL_STUB_UNWIND_INFO_3 \ | |
477 | "18:" \ | |
478 | : "=m" (futex), "=&a" (ignore) \ | |
479 | : "m" (futex), "i" (MULTIPLE_THREADS_OFFSET) \ | |
480 | : "memory"); \ | |
481 | else \ | |
482 | { \ | |
483 | int ignore2; \ | |
484 | __asm __volatile (__lll_unlock_asm \ | |
485 | "jne _L_unlock_%=\n\t" \ | |
486 | ".subsection 1\n\t" \ | |
487 | ".type _L_unlock_%=,@function\n" \ | |
488 | "_L_unlock_%=:\n" \ | |
489 | "1:\tleal %0, %%eax\n" \ | |
490 | "0:\tmovl %5, %%ecx\n" \ | |
491 | "2:\tcall __lll_unlock_wake\n" \ | |
492 | "3:\tjmp 18f\n" \ | |
493 | "4:\t.size _L_unlock_%=, 4b-1b\n\t" \ | |
494 | ".previous\n" \ | |
495 | LLL_STUB_UNWIND_INFO_4 \ | |
496 | "18:" \ | |
497 | : "=m" (futex), "=&a" (ignore), "=&c" (ignore2) \ | |
498 | : "i" (MULTIPLE_THREADS_OFFSET), "m" (futex), \ | |
2458c748 | 499 | "g" ((int) (private)) \ |
e51deae7 UD |
500 | : "memory"); \ |
501 | } \ | |
502 | }) | |
503 | ||
504 | #define lll_robust_unlock(futex, private) \ | |
505 | (void) \ | |
506 | ({ int ignore, ignore2; \ | |
507 | __asm __volatile (LOCK_INSTR "andl %3, %0\n\t" \ | |
508 | "jne _L_robust_unlock_%=\n\t" \ | |
509 | ".subsection 1\n\t" \ | |
510 | ".type _L_robust_unlock_%=,@function\n" \ | |
511 | "_L_robust_unlock_%=:\n\t" \ | |
512 | "1:\tleal %0, %%eax\n" \ | |
513 | "0:\tmovl %5, %%ecx\n" \ | |
514 | "2:\tcall __lll_unlock_wake\n" \ | |
515 | "3:\tjmp 18f\n" \ | |
516 | "4:\t.size _L_robust_unlock_%=, 4b-1b\n\t" \ | |
517 | ".previous\n" \ | |
518 | LLL_STUB_UNWIND_INFO_4 \ | |
519 | "18:" \ | |
520 | : "=m" (futex), "=&a" (ignore), "=&c" (ignore2) \ | |
2458c748 AJ |
521 | : "i" (FUTEX_WAITERS), "m" (futex), \ |
522 | "g" ((int) (private)) \ | |
e51deae7 UD |
523 | : "memory"); \ |
524 | }) | |
525 | ||
526 | ||
527 | #define lll_robust_dead(futex, private) \ | |
528 | (void) \ | |
529 | ({ int __ignore; \ | |
530 | register int _nr asm ("edx") = 1; \ | |
531 | __asm __volatile (LOCK_INSTR "orl %5, (%2)\n\t" \ | |
532 | LLL_EBX_LOAD \ | |
533 | LLL_ENTER_KERNEL \ | |
534 | LLL_EBX_LOAD \ | |
535 | : "=a" (__ignore) \ | |
536 | : "0" (SYS_futex), LLL_EBX_REG (&(futex)), \ | |
537 | "c" (__lll_private_flag (FUTEX_WAKE, private)), \ | |
538 | "d" (_nr), "i" (FUTEX_OWNER_DIED), \ | |
539 | "i" (offsetof (tcbhead_t, sysinfo))); \ | |
540 | }) | |
76a50749 UD |
541 | |
542 | #define lll_islocked(futex) \ | |
71451de2 | 543 | (futex != LLL_LOCK_INITIALIZER) |
76a50749 | 544 | |
76a50749 UD |
545 | /* The kernel notifies a process with uses CLONE_CLEARTID via futex |
546 | wakeup when the clone terminates. The memory location contains the | |
547 | thread ID while the clone is running and is reset to zero | |
548 | afterwards. | |
549 | ||
550 | The macro parameter must not have any side effect. */ | |
76a50749 UD |
551 | #define lll_wait_tid(tid) \ |
552 | do { \ | |
553 | int __ignore; \ | |
554 | register __typeof (tid) _tid asm ("edx") = (tid); \ | |
555 | if (_tid != 0) \ | |
949ec764 | 556 | __asm __volatile (LLL_EBX_LOAD \ |
76a50749 | 557 | "1:\tmovl %1, %%eax\n\t" \ |
949ec764 | 558 | LLL_ENTER_KERNEL \ |
76a50749 | 559 | "cmpl $0, (%%ebx)\n\t" \ |
ab9a9ff8 | 560 | "jne 1b\n\t" \ |
949ec764 | 561 | LLL_EBX_LOAD \ |
76a50749 | 562 | : "=&a" (__ignore) \ |
949ec764 | 563 | : "i" (SYS_futex), LLL_EBX_REG (&tid), "S" (0), \ |
097eca29 | 564 | "c" (FUTEX_WAIT), "d" (_tid), \ |
b576fca1 UD |
565 | "i" (offsetof (tcbhead_t, sysinfo)) \ |
566 | : "memory"); \ | |
76a50749 UD |
567 | } while (0) |
568 | ||
569 | extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime) | |
570 | __attribute__ ((regparm (2))) attribute_hidden; | |
571 | #define lll_timedwait_tid(tid, abstime) \ | |
572 | ({ \ | |
573 | int __result = 0; \ | |
574 | if (tid != 0) \ | |
575 | { \ | |
31195be2 | 576 | if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) \ |
76a50749 UD |
577 | __result = EINVAL; \ |
578 | else \ | |
579 | __result = __lll_timedwait_tid (&tid, abstime); \ | |
580 | } \ | |
581 | __result; }) | |
582 | ||
e51deae7 | 583 | #endif /* !__ASSEMBLER__ */ |
76a50749 UD |
584 | |
585 | #endif /* lowlevellock.h */ |