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