(pthread_barrier_wait): Don't save, load, and restore %esi for last thread.
[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
261 #ifdef I386_USE_SYSENTER
262 # ifdef SHARED
263 # define LLL_TID_ENTER_KERNEL   "call *%%gs:%P6\n\t"
264 # else
265 # define LLL_TID_ENTER_KERNEL   "call *_dl_sysinfo\n\t"
266 # endif
267 #else
268 # define LLL_TID_ENTER_KERNEL   "int $0x80\n\t"
269 #endif
270
271 #define lll_wait_tid(tid) \
272   do {                                                                        \
273     int __ignore;                                                             \
274     register __typeof (tid) _tid asm ("edx") = (tid);                         \
275     if (_tid != 0)                                                            \
276       __asm __volatile (LLL_TID_EBX_LOAD                                      \
277                         "1:\tmovl %1, %%eax\n\t"                              \
278                         LLL_TID_ENTER_KERNEL                                  \
279                         "cmpl $0, (%%ebx)\n\t"                                \
280                         "jne,pn 1b\n\t"                                       \
281                         LLL_TID_EBX_LOAD                                      \
282                         : "=&a" (__ignore)                                    \
283                         : "i" (SYS_futex), LLL_TID_EBX_REG (&tid), "S" (0),   \
284                           "c" (FUTEX_WAIT), "d" (_tid),                       \
285                           "i" (offsetof (tcbhead_t, sysinfo)));               \
286   } while (0)
287
288 extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime)
289      __attribute__ ((regparm (2))) attribute_hidden;
290 #define lll_timedwait_tid(tid, abstime) \
291   ({                                                                          \
292     int __result = 0;                                                         \
293     if (tid != 0)                                                             \
294       {                                                                       \
295         if (abstime == NULL || abstime->tv_nsec >= 1000000000)                \
296           __result = EINVAL;                                                  \
297         else                                                                  \
298           __result = __lll_timedwait_tid (&tid, abstime);                     \
299       }                                                                       \
300     __result; })
301
302
303 #define lll_wake_tid(tid) \
304   do {                                                                        \
305     int __ignore;                                                             \
306     (tid) = 0;                                                                \
307     __asm __volatile (LLL_TID_EBX_LOAD                                        \
308                       LLL_TID_ENTER_KERNEL                                    \
309                       LLL_TID_EBX_LOAD                                        \
310                       : "=a" (__ignore)                                       \
311                       : "0" (SYS_futex), LLL_TID_EBX_REG (&(tid)), "S" (0),   \
312                         "c" (FUTEX_WAKE), "d" (0x7fffffff)                    \
313                         "i" (offsetof (tcbhead_t, sysinfo)));                 \
314   } while (0)
315
316
317 /* Conditional variable handling.  */
318
319 extern void __lll_cond_wait (pthread_cond_t *cond)
320      __attribute ((regparm (1))) attribute_hidden;
321 extern int __lll_cond_timedwait (pthread_cond_t *cond,
322                                  const struct timespec *abstime)
323      __attribute ((regparm (2))) attribute_hidden;
324 extern void __lll_cond_wake (pthread_cond_t *cond)
325      __attribute ((regparm (1))) attribute_hidden;
326 extern void __lll_cond_broadcast (pthread_cond_t *cond)
327      __attribute ((regparm (1))) attribute_hidden;
328
329
330 #define lll_cond_wait(cond) \
331   __lll_cond_wait (cond)
332 #define lll_cond_timedwait(cond, abstime) \
333   __lll_cond_timedwait (cond, abstime)
334 #define lll_cond_wake(cond) \
335   __lll_cond_wake (cond)
336 #define lll_cond_broadcast(cond) \
337   __lll_cond_broadcast (cond)
338
339
340 #endif  /* lowlevellock.h */