Update.
[platform/upstream/glibc.git] / nptl / sysdeps / unix / sysv / linux / x86_64 / lowlevellock.h
1 /* Copyright (C) 2002, 2003 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
39
40 /* Initializer for compatibility lock.  */
41 #define LLL_MUTEX_LOCK_INITIALIZER (0)
42
43
44 /* Does not preserve %eax and %ecx.  */
45 extern int __lll_mutex_lock_wait (int *__futex, int __val) attribute_hidden;
46 /* Does not preserver %eax, %ecx, and %edx.  */
47 extern int __lll_mutex_timedlock_wait (int *__futex, int __val,
48                                        const struct timespec *__abstime)
49      attribute_hidden;
50 /* Preserves all registers but %eax.  */
51 extern int __lll_mutex_unlock_wait (int *__futex) attribute_hidden;
52
53
54 #define lll_mutex_trylock(futex) \
55   ({ unsigned char ret;                                                       \
56      __asm __volatile (LOCK_INSTR "cmpxchgl %2, %1; setne %0"                 \
57                        : "=a" (ret), "=m" (futex)                             \
58                        : "r" (1), "1" (futex), "0" (0)                        \
59                        : "memory");                                           \
60      ret; })
61
62
63 #define lll_mutex_lock(futex) \
64   (void) ({ int ignore1, ignore2;                                             \
65             __asm __volatile (LOCK_INSTR "xaddl %0, %2\n\t"                   \
66                               "testl %0, %0\n\t"                              \
67                               "jne 1f\n\t"                                    \
68                               ".subsection 1\n"                               \
69                               "1:\tleaq %2, %%rsi\n\t"                        \
70                               "subq $128, %%rsp\n\t"                          \
71                               "callq __lll_mutex_lock_wait\n\t"               \
72                               "addq $128, %%rsp\n\t"                          \
73                               "jmp 2f\n\t"                                    \
74                               ".previous\n"                                   \
75                               "2:"                                            \
76                               : "=S" (ignore1), "=&D" (ignore2), "=m" (futex) \
77                               : "0" (1), "2" (futex)                          \
78                               : "memory"); })
79
80
81 #define lll_mutex_timedlock(futex, timeout) \
82   ({ int result, ignore1, ignore2, ignore3;                                   \
83      __asm __volatile (LOCK_INSTR "xaddl %0, %4\n\t"                          \
84                        "testl %0, %0\n\t"                                     \
85                        "jne 1f\n\t"                                           \
86                        ".subsection 1\n"                                      \
87                        "1:\tleaq %4, %%rdi\n\t"                               \
88                        "movq %7, %%rdx\n\t"                                   \
89                        "subq $128, %%rsp\n\t"                                 \
90                        "callq __lll_mutex_timedlock_wait\n\t"                 \
91                        "addq $128, %%rsp\n\t"                                 \
92                        "jmp 2f\n\t"                                           \
93                        ".previous\n"                                          \
94                        "2:"                                                   \
95                        : "=S" (result), "=&D" (ignore1), "=&a" (ignore2),     \
96                          "=&d" (ignore3), "=m" (futex)                        \
97                        : "0" (1), "4" (futex), "m" (timeout)                  \
98                        : "memory", "cx", "cc", "r10");                        \
99      result; })
100
101
102 #define lll_mutex_unlock(futex) \
103   (void) ({ int ignore;                                                       \
104             __asm __volatile (LOCK_INSTR "decl %0\n\t"                        \
105                               "jne 1f\n\t"                                    \
106                               ".subsection 1\n"                               \
107                               "1:\tleaq %0, %%rdi\n\t"                        \
108                               "subq $128, %%rsp\n\t"                          \
109                               "callq __lll_mutex_unlock_wake\n\t"             \
110                               "addq $128, %%rsp\n\t"                          \
111                               "jmp 2f\n\t"                                    \
112                               ".previous\n"                                   \
113                               "2:"                                            \
114                               : "=m" (futex), "=&D" (ignore)                  \
115                               : "0" (futex)                                   \
116                               : "memory"); })
117
118
119 #define lll_mutex_islocked(futex) \
120   (futex != 0)
121
122
123 /* We have a separate internal lock implementation which is not tied
124    to binary compatibility.  */
125
126 /* Type for lock object.  */
127 typedef int lll_lock_t;
128
129 /* Initializers for lock.  */
130 #define LLL_LOCK_INITIALIZER            (1)
131 #define LLL_LOCK_INITIALIZER_LOCKED     (0)
132
133
134 extern int __lll_lock_wait (int *__futex, int val) attribute_hidden;
135 extern int __lll_unlock_wake (int *__futex) attribute_hidden;
136 extern int lll_unlock_wake_cb (int *__futex) attribute_hidden;
137
138
139 /* The states of a lock are:
140     1  -  untaken
141     0  -  taken by one user
142    <0  -  taken by more users */
143
144
145 #if defined NOT_IN_libc || defined UP
146 # define lll_trylock(futex) \
147   ({ unsigned char ret;                                                       \
148      __asm __volatile (LOCK_INSTR "cmpxchgl %2, %1; setne %0"                 \
149                        : "=a" (ret), "=m" (futex)                             \
150                        : "r" (0), "1" (futex), "0" (1)                        \
151                        : "memory");                                           \
152      ret; })
153
154
155 # define lll_lock(futex) \
156   (void) ({ int ignore1, ignore2;                                             \
157             __asm __volatile (LOCK_INSTR "xaddl %0, %2\n\t"                   \
158                               "jne 1f\n\t"                                    \
159                               ".subsection 1\n"                               \
160                               "1:\tleaq %2, %%rsi\n\t"                        \
161                               "subq $128, %%rsp\n\t"                          \
162                               "callq __lll_lock_wait\n\t"                     \
163                               "addq $128, %%rsp\n\t"                          \
164                               "jmp 2f\n\t"                                    \
165                               ".previous\n"                                   \
166                               "2:"                                            \
167                               : "=S" (ignore1), "=&D" (ignore2), "=m" (futex) \
168                               : "0" (-1), "2" (futex)                         \
169                               : "memory"); })
170
171
172 # define lll_unlock(futex) \
173   (void) ({ int ignore;                                                       \
174             __asm __volatile (LOCK_INSTR "addl $1,%0\n\t"                     \
175                               "jng 1f\n\t"                                    \
176                               ".subsection 1\n"                               \
177                               "1:\tleaq %0, %%rdi\n\t"                        \
178                               "subq $128, %%rsp\n\t"                          \
179                               "callq __lll_unlock_wake\n\t"                   \
180                               "addq $128, %%rsp\n\t"                          \
181                               "jmp 2f\n\t"                                    \
182                               ".previous\n"                                   \
183                               "2:"                                            \
184                               : "=m" (futex), "=&D" (ignore)                  \
185                               : "0" (futex)                                   \
186                               : "memory"); })
187 #else
188 /* Special versions of the macros for use in libc itself.  They avoid
189    the lock prefix when the thread library is not used.
190
191    XXX In future we might even want to avoid it on UP machines.  */
192
193 # define lll_trylock(futex) \
194   ({ unsigned char ret;                                                       \
195      __asm __volatile ("cmpl $0, __libc_multiple_threads(%%rip)\n\t"          \
196                        "je 0f\n\t"                                            \
197                        "lock\n"                                               \
198                        "0:\tcmpxchgl %2, %1; setne %0"                        \
199                        : "=a" (ret), "=m" (futex)                             \
200                        : "r" (0), "1" (futex), "0" (1)                        \
201                        : "memory");                                           \
202      ret; })
203
204
205 # define lll_lock(futex) \
206   (void) ({ int ignore1, ignore2;                                             \
207             __asm __volatile ("cmpl $0, __libc_multiple_threads(%%rip)\n\t"   \
208                               "je 0f\n\t"                                     \
209                               "lock\n"                                        \
210                               "0:\txaddl %0, %2\n\t"                          \
211                               "jne 1f\n\t"                                    \
212                               ".subsection 1\n"                               \
213                               "1:\tleaq %2, %%rsi\n\t"                        \
214                               "subq $128, %%rsp\n\t"                          \
215                               "callq __lll_lock_wait\n\t"                     \
216                               "addq $128, %%rsp\n\t"                          \
217                               "jmp 2f\n\t"                                    \
218                               ".previous\n"                                   \
219                               "2:"                                            \
220                               : "=D" (ignore1), "=&S" (ignore2), "=m" (futex) \
221                               : "0" (-1), "2" (futex)                         \
222                               : "memory"); })
223
224
225 # define lll_unlock(futex) \
226   (void) ({ int ignore;                                                       \
227             __asm __volatile ("cmpl $0, __libc_multiple_threads(%%rip)\n\t"   \
228                               "je 0f\n\t"                                     \
229                               "lock\n"                                        \
230                               "0:\taddl $1,%0\n\t"                            \
231                               "jng 1f\n\t"                                    \
232                               ".subsection 1\n"                               \
233                               "1:\tleaq %0, %%rdi\n\t"                        \
234                               "subq $128, %%rsp\n\t"                          \
235                               "callq __lll_unlock_wake\n\t"                   \
236                               "addq $128, %%rsp\n\t"                          \
237                               "jmp 2f\n\t"                                    \
238                               ".previous\n"                                   \
239                               "2:"                                            \
240                               : "=m" (futex), "=&D" (ignore)                  \
241                               : "0" (futex)                                   \
242                               : "memory"); })
243 #endif
244
245
246 #define lll_islocked(futex) \
247   (futex != 0)
248
249
250 /* The kernel notifies a process with uses CLONE_CLEARTID via futex
251    wakeup when the clone terminates.  The memory location contains the
252    thread ID while the clone is running and is reset to zero
253    afterwards.
254
255    The macro parameter must not have any side effect.  */
256 #define lll_wait_tid(tid) \
257   do {                                                                        \
258     int __ignore;                                                             \
259     register __typeof (tid) _tid asm ("edx") = (tid);                         \
260     if (_tid != 0)                                                            \
261       __asm __volatile ("xorq %%r10, %%r10\n\t"                               \
262                         "1:\tmovq %3, %%rax\n\t"                              \
263                         "syscall\n\t"                                         \
264                         "cmpl $0, (%%rdi)\n\t"                                \
265                         "jne 1b"                                              \
266                         : "=&a" (__ignore)                                    \
267                         : "S" (FUTEX_WAIT), "i" (SYS_futex), "D" (&tid),      \
268                           "d" (_tid)                                          \
269                         : "memory", "cc", "r10", "r11", "cx");                \
270   } while (0)
271
272 extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime)
273      attribute_hidden;
274 #define lll_timedwait_tid(tid, abstime) \
275   ({                                                                          \
276     int __result = 0;                                                         \
277     if (tid != 0)                                                             \
278       {                                                                       \
279         if (abstime == NULL || abstime->tv_nsec >= 1000000000)                \
280           __result = EINVAL;                                                  \
281         else                                                                  \
282           __result = __lll_timedwait_tid (&tid, abstime);                     \
283       }                                                                       \
284     __result; })
285
286
287 /* Conditional variable handling.  */
288
289 extern void __lll_cond_wait (pthread_cond_t *cond) attribute_hidden;
290 extern int __lll_cond_timedwait (pthread_cond_t *cond,
291                                  const struct timespec *abstime)
292      attribute_hidden;
293 extern void __lll_cond_wake (pthread_cond_t *cond) attribute_hidden;
294 extern void __lll_cond_broadcast (pthread_cond_t *cond) attribute_hidden;
295
296
297 #define lll_cond_wait(cond) \
298   __lll_cond_wait (cond)
299 #define lll_cond_timedwait(cond, abstime) \
300   __lll_cond_timedwait (cond, abstime)
301 #define lll_cond_wake(cond) \
302   __lll_cond_wake (cond)
303 #define lll_cond_broadcast(cond) \
304   __lll_cond_broadcast (cond)
305
306
307 #endif  /* lowlevellock.h */