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